Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: df7961fbd277
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: fed64fe88a66
Choose a head ref
  • 2 commits
  • 3 files changed
  • 1 contributor

Commits on Dec 13, 2015

  1. Copy the full SHA
    d6f4cc1 View commit details
  2. Copy the full SHA
    fed64fe View commit details
Showing with 47 additions and 12 deletions.
  1. +36 −9 lib/ruby/stdlib/ostruct.rb
  2. +0 −3 test/mri/excludes/TC_OpenStruct.rb
  3. +11 −0 test/mri/ostruct/test_ostruct.rb
45 changes: 36 additions & 9 deletions lib/ruby/stdlib/ostruct.rb
Original file line number Diff line number Diff line change
@@ -90,7 +90,6 @@ def initialize(hash=nil)
hash.each_pair do |k, v|
k = k.to_sym
@table[k] = v
new_ostruct_member(k)
end
end
end
@@ -99,7 +98,6 @@ def initialize(hash=nil)
def initialize_copy(orig)
super
@table = @table.dup
@table.each_key{|key| new_ostruct_member(key)}
end

#
@@ -141,7 +139,6 @@ def marshal_dump
#
def marshal_load(x)
@table = x
@table.each_key{|key| new_ostruct_member(key)}
end

#
@@ -173,16 +170,23 @@ def new_ostruct_member(name)
end
protected :new_ostruct_member

def respond_to_missing?(mid, include_private = false)
mname = mid.to_s.chomp("=").to_sym
@table.key?(mname) || super
end

def method_missing(mid, *args) # :nodoc:
mname = mid.id2name
len = args.length
if mname.chomp!('=')
if mname = mid[/.*(?==\z)/m]
if len != 1
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
end
modifiable[new_ostruct_member(mname)] = args[0]
elsif len == 0
@table[mid]
if @table.key?(mid)
new_ostruct_member(mid)
@table[mid]
end
else
err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args
err.set_backtrace caller(1)
@@ -210,6 +214,24 @@ def []=(name, value)
modifiable[new_ostruct_member(name)] = value
end

#
# Retrieves the value object corresponding to the each +name+
# objects repeatedly.
#
# address = OpenStruct.new('city' => "Anytown NC", 'zip' => 12345)
# person = OpenStruct.new('name' => 'John Smith', 'address' => address)
# person.dig(:address, 'zip') # => 12345
# person.dig(:business_address, 'zip') # => nil
#
def dig(name, *names)
begin
name = name.to_sym
rescue NoMethodError
return
end
@table.dig(name, *names)
end

#
# Remove the named field from the object. Returns the value that the field
# contained if it was defined.
@@ -222,8 +244,13 @@ def []=(name, value)
#
def delete_field(name)
sym = name.to_sym
singleton_class.__send__(:remove_method, sym, "#{sym}=")
@table.delete sym
begin
singleton_class.__send__(:remove_method, sym, "#{sym}=")
rescue NameError
end
@table.delete(sym) do
raise NameError.new("no field `#{sym}' in #{self}", sym)
end
end

InspectKey = :__inspect_key__ # :nodoc:
@@ -283,4 +310,4 @@ def eql?(other)
def hash
@table.hash
end
end
end
3 changes: 0 additions & 3 deletions test/mri/excludes/TC_OpenStruct.rb
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
exclude :test_each_pair, ''
exclude :test_frozen, ''
exclude :test_method_missing, ''
11 changes: 11 additions & 0 deletions test/mri/ostruct/test_ostruct.rb
Original file line number Diff line number Diff line change
@@ -95,6 +95,17 @@ def test_getter
assert_equal :bar, os['foo']
end

def test_dig
os1 = OpenStruct.new
os2 = OpenStruct.new
os1.child = os2
os2.foo = :bar
os2.child = [42]
assert_equal :bar, os1.dig("child", :foo)
assert_nil os1.dig("parent", :foo)
assert_nil os1.dig("child", 0)
end

def test_to_h
h = {name: "John Smith", age: 70, pension: 300}
os = OpenStruct.new(h)