File: each.rb

package info (click to toggle)
ruby3.1 3.1.2-7%2Bdeb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 132,892 kB
  • sloc: ruby: 1,154,753; ansic: 736,782; yacc: 46,445; pascal: 10,401; sh: 3,931; cpp: 1,158; python: 838; makefile: 787; asm: 462; javascript: 382; lisp: 97; sed: 94; perl: 62; awk: 36; xml: 4
file content (124 lines) | stat: -rw-r--r-- 3,311 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
describe :hash_each, shared: true do

  # This is inconsistent with below, MRI checks the block arity in rb_hash_each_pair()
  it "yields a [[key, value]] Array for each pair to a block expecting |*args|" do
    all_args = []
    { 1 => 2, 3 => 4 }.send(@method) { |*args| all_args << args }
    all_args.sort.should == [[[1, 2]], [[3, 4]]]
  end

  it "yields the key and value of each pair to a block expecting |key, value|" do
    r = {}
    h = { a: 1, b: 2, c: 3, d: 5 }
    h.send(@method) { |k,v| r[k.to_s] = v.to_s }.should equal(h)
    r.should == { "a" => "1", "b" => "2", "c" => "3", "d" => "5" }
  end

  it "yields the key only to a block expecting |key,|" do
    ary = []
    h = { "a" => 1, "b" => 2, "c" => 3 }
    h.send(@method) { |k,| ary << k }
    ary.sort.should == ["a", "b", "c"]
  end

  ruby_version_is ""..."3.0" do
    it "yields 2 values and not an Array of 2 elements when given a callable of arity 2" do
      obj = Object.new
      def obj.foo(key, value)
        ScratchPad << key << value
      end

      ScratchPad.record([])
      { "a" => 1 }.send(@method, &obj.method(:foo))
      ScratchPad.recorded.should == ["a", 1]

      ScratchPad.record([])
      { "a" => 1 }.send(@method, &-> key, value { ScratchPad << key << value })
      ScratchPad.recorded.should == ["a", 1]
    end
  end

  ruby_version_is "3.0" do
    it "always yields an Array of 2 elements, even when given a callable of arity 2" do
      obj = Object.new
      def obj.foo(key, value)
      end

      -> {
        { "a" => 1 }.send(@method, &obj.method(:foo))
      }.should raise_error(ArgumentError)

      -> {
        { "a" => 1 }.send(@method, &-> key, value { })
      }.should raise_error(ArgumentError)
    end
  end

  it "yields an Array of 2 elements when given a callable of arity 1" do
    obj = Object.new
    def obj.foo(key_value)
      ScratchPad << key_value
    end

    ScratchPad.record([])
    { "a" => 1 }.send(@method, &obj.method(:foo))
    ScratchPad.recorded.should == [["a", 1]]
  end

  it "raises an error for a Hash when an arity enforcing callable of arity >2 is passed in" do
    obj = Object.new
    def obj.foo(key, value, extra)
    end

    -> {
      { "a" => 1 }.send(@method, &obj.method(:foo))
    }.should raise_error(ArgumentError)
  end

  it "uses the same order as keys() and values()" do
    h = { a: 1, b: 2, c: 3, d: 5 }
    keys = []
    values = []

    h.send(@method) do |k, v|
      keys << k
      values << v
    end

    keys.should == h.keys
    values.should == h.values
  end

  # Confirming the argument-splatting works from child class for both k, v and [k, v]
  it "properly expands (or not) child class's 'each'-yielded args" do
    cls1 = Class.new(Hash) do
      attr_accessor :k_v
      def each
        super do |k, v|
          @k_v = [k, v]
          yield k, v
        end
      end
    end

    cls2 = Class.new(Hash) do
      attr_accessor :k_v
      def each
        super do |k, v|
          @k_v = [k, v]
          yield([k, v])
        end
      end
    end

    obj1 = cls1.new
    obj1['a'] = 'b'
    obj1.map {|k, v| [k, v]}.should == [['a', 'b']]
    obj1.k_v.should == ['a', 'b']

    obj2 = cls2.new
    obj2['a'] = 'b'
    obj2.map {|k, v| [k, v]}.should == [['a', 'b']]
    obj2.k_v.should == ['a', 'b']
  end
end