ruby-changes:49249
From: nagachika <ko1@a...>
Date: Wed, 20 Dec 2017 23:57:08 +0900 (JST)
Subject: [ruby-changes:49249] nagachika:r61364 (ruby_2_4): merge revision(s) 57887: [Backport #13159]
nagachika 2017-12-20 23:56:48 +0900 (Wed, 20 Dec 2017) New Revision: 61364 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=61364 Log: merge revision(s) 57887: [Backport #13159] lib/ostruct.rb: [DOC] revise docs for OpenStruct * update paragraph on implementation: define_singleton_method is used, not define_method * add call-seq with return values for each_pair * adopt description of dig from Array and Hash * fix description of the hash method * :nodoc: initialize_copy, respond_to_missing? * other small improvements, e.g. use the term `attribute' in the docs (instead of `member'), which is clearer for users of the class * improve code examples: e.g. use more consistent style (always use double quotes, drop `p' and `puts', ...), update inspect output, use example data that is not prone to change (like population) * add more code examples * fix some small errors and grammar [ruby-core:79265] [Bug #13159] Modified directories: branches/ruby_2_4/ Modified files: branches/ruby_2_4/lib/ostruct.rb branches/ruby_2_4/version.h Index: ruby_2_4/lib/ostruct.rb =================================================================== --- ruby_2_4/lib/ostruct.rb (revision 61363) +++ ruby_2_4/lib/ostruct.rb (revision 61364) @@ -15,56 +15,58 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_4/lib/ostruct.rb#L15 # accomplished by using Ruby's metaprogramming to define methods on the class # itself. # -# == Examples: +# == Examples # -# require 'ostruct' +# require "ostruct" # # person = OpenStruct.new -# person.name = "John Smith" -# person.age = 70 -# person.pension = 300 -# -# puts person.name # -> "John Smith" -# puts person.age # -> 70 -# puts person.address # -> nil -# -# An OpenStruct employs a Hash internally to store the methods and values and -# can even be initialized with one: -# -# australia = OpenStruct.new(:country => "Australia", :population => 20_000_000) -# p australia # -> <OpenStruct country="Australia" population=20000000> -# -# Hash keys with spaces or characters that would normally not be able to use for -# method calls (e.g. ()[]*) will not be immediately available on the -# OpenStruct object as a method for retrieval or assignment, but can be still be -# reached through the Object#send method. +# person.name = "John Smith" +# person.age = 70 +# +# person.name # => "John Smith" +# person.age # => 70 +# person.address # => nil +# +# An OpenStruct employs a Hash internally to store the attributes and values +# and can even be initialized with one: +# +# australia = OpenStruct.new(:country => "Australia", :capital => "Canberra") +# # => #<OpenStruct country="Australia", capital="Canberra"> +# +# Hash keys with spaces or characters that could normally not be used for +# method calls (e.g. <code>()[]*</code>) will not be immediately available +# on the OpenStruct object as a method for retrieval or assignment, but can +# still be reached through the Object#send method. # # measurements = OpenStruct.new("length (in inches)" => 24) -# measurements.send("length (in inches)") # -> 24 +# measurements.send("length (in inches)") # => 24 # -# data_point = OpenStruct.new(:queued? => true) -# data_point.queued? # -> true -# data_point.send("queued?=",false) -# data_point.queued? # -> false +# message = OpenStruct.new(:queued? => true) +# message.queued? # => true +# message.send("queued?=", false) +# message.queued? # => false +# +# Removing the presence of an attribute requires the execution of the +# delete_field method as setting the property value to +nil+ will not +# remove the attribute. # -# Removing the presence of a method requires the execution the delete_field -# method as setting the property value to +nil+ will not remove the method. +# first_pet = OpenStruct.new(:name => "Rowdy", :owner => "John Smith") +# second_pet = OpenStruct.new(:name => "Rowdy") # -# first_pet = OpenStruct.new(:name => 'Rowdy', :owner => 'John Smith') # first_pet.owner = nil -# second_pet = OpenStruct.new(:name => 'Rowdy') -# -# first_pet == second_pet # -> false +# first_pet # => #<OpenStruct name="Rowdy", owner=nil> +# first_pet == second_pet # => false # # first_pet.delete_field(:owner) -# first_pet == second_pet # -> true +# first_pet # => #<OpenStruct name="Rowdy"> +# first_pet == second_pet # => true # # -# == Implementation: +# == Implementation # # An OpenStruct utilizes Ruby's method lookup structure to find and define the -# necessary methods for properties. This is accomplished through the method -# method_missing and define_method. +# necessary methods for properties. This is accomplished through the methods +# method_missing and define_singleton_method. # # This should be a consideration if there is a concern about the performance of # the objects that are created, as there is much more overhead in the setting @@ -80,11 +82,11 @@ class OpenStruct https://github.com/ruby/ruby/blob/trunk/ruby_2_4/lib/ostruct.rb#L82 # (can be a Hash, an OpenStruct or a Struct). # For example: # - # require 'ostruct' - # hash = { "country" => "Australia", :population => 20_000_000 } + # require "ostruct" + # hash = { "country" => "Australia", :capital => "Canberra" } # data = OpenStruct.new(hash) # - # p data # -> <OpenStruct country="Australia" population=20000000> + # data # => #<OpenStruct country="Australia", capital="Canberra"> # def initialize(hash=nil) @table = {} @@ -96,33 +98,35 @@ class OpenStruct https://github.com/ruby/ruby/blob/trunk/ruby_2_4/lib/ostruct.rb#L98 end end - # Duplicate an OpenStruct object members. - def initialize_copy(orig) + # Duplicates an OpenStruct object's Hash table. + def initialize_copy(orig) # :nodoc: super @table = @table.dup end # # Converts the OpenStruct to a hash with keys representing - # each attribute (as symbols) and their corresponding values - # Example: + # each attribute (as symbols) and their corresponding values. # - # require 'ostruct' - # data = OpenStruct.new("country" => "Australia", :population => 20_000_000) - # data.to_h # => {:country => "Australia", :population => 20000000 } + # require "ostruct" + # data = OpenStruct.new("country" => "Australia", :capital => "Canberra") + # data.to_h # => {:country => "Australia", :capital => "Canberra" } # def to_h @table.dup end # - # Yields all attributes (as a symbol) along with the corresponding values - # or returns an enumerator if not block is given. - # Example: - # - # require 'ostruct' - # data = OpenStruct.new("country" => "Australia", :population => 20_000_000) - # data.each_pair.to_a # => [[:country, "Australia"], [:population, 20000000]] + # :call-seq: + # ostruct.each_pair {|name, value| block } -> ostruct + # ostruct.each_pair -> Enumerator + # + # Yields all attributes (as symbols) along with the corresponding values + # or returns an enumerator if no block is given. + # + # require "ostruct" + # data = OpenStruct.new("country" => "Australia", :capital => "Canberra") + # data.each_pair.to_a # => [[:country, "Australia"], [:capital, "Canberra"]] # def each_pair return to_enum(__method__) { @table.size } unless block_given? @@ -186,7 +190,7 @@ class OpenStruct https://github.com/ruby/ruby/blob/trunk/ruby_2_4/lib/ostruct.rb#L190 super end - def respond_to_missing?(mid, include_private = false) + def respond_to_missing?(mid, include_private = false) # :nodoc: mname = mid.to_s.chomp("=").to_sym @table&.key?(mname) || super end @@ -210,34 +214,54 @@ class OpenStruct https://github.com/ruby/ruby/blob/trunk/ruby_2_4/lib/ostruct.rb#L214 end end - # Returns the value of a member. # - # person = OpenStruct.new('name' => 'John Smith', 'age' => 70) - # person[:age] # => 70, same as ostruct.age + # :call-seq: + # ostruct[name] -> object + # + # Returns the value of an attribute. + # + # require "ostruct" + # person = OpenStruct.new("name" => "John Smith", "age" => 70) + # person[:age] # => 70, same as person.age # def [](name) @table[name.to_sym] end # - # Sets the value of a member. + # :call-seq: + # ostruct[name] = obj -> obj # - # person = OpenStruct.new('name' => 'John Smith', 'age' => 70) - # person[:age] = 42 # => equivalent to ostruct.age = 42 - # person.age # => 42 + # Sets the value of an attribute. + # + # require "ostruct" + # person = OpenStruct.new("name" => "John Smith", "age" => 70) + # person[:age] = 42 # equivalent to person.age = 42 + # person.age # => 42 # def []=(name, value) modifiable?[new_ostruct_member!(name)] = value end # - # Retrieves the value object corresponding to the each +name+ - # objects repeatedly. + # :call-seq: + # ostruct.dig(name, ...) -> object + # + # Extracts the nested value specified by the sequence of +name+ + # objects by calling +dig+ at each step, returning +nil+ if any + # intermediate step is +nil+. + # + # require "ostruct" + # address = OpenStruct.new("city" => "Anytown NC", "zip" => 12345) + # person = OpenStruct.new("name" => "John Smith", "address" => address) # - # 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 + # person.dig(:address, "zip") # => 12345 + # person.dig(:business_address, "zip") # => nil + # + # data = OpenStruct.new(:array => [1, [2, 3]]) + # + # data.dig(:array, 1, 0) # => 2 + # data.dig(:array, 0, 0) # TypeError: Integer does not have #dig method # def dig(name, *names) begin @@ -249,14 +273,20 @@ class OpenStruct https://github.com/ruby/ruby/blob/trunk/ruby_2_4/lib/ostruct.rb#L273 end # - # Remove the named field from the object. Returns the value that the field + # Removes the named field from the object. Returns the value that the field # contained if it was defined. # - # require 'ostruct' + # require "ostruct" + # + # person = OpenStruct.new(name: "John", age: 70, pension: 300) + # + # person.delete_field("age") # => 70 + # person # => #<OpenStruct name="John", pension=300> # - # person = OpenStruct.new('name' => 'John Smith', 'age' => 70) + # Setting the value to +nil+ will not remove the attribute: # - # person.delete_field('name') # => 'John Smith' + # person.pension = nil + # person # => #<OpenStruct name="John", pension=nil> # def delete_field(name) sym = name.to_sym @@ -306,6 +336,14 @@ class OpenStruct https://github.com/ruby/ruby/blob/trunk/ruby_2_4/lib/ostruct.rb#L336 # +other+ when +other+ is an OpenStruct and the two objects' Hash tables are # equal. # + # require "ostruct" + # first_pet = OpenStruct.new("name" => "Rowdy") + # second_pet = OpenStruct.new(:name => "Rowdy") + # third_pet = OpenStruct.new("name" => "Rowdy", :age => nil) + # + # first_pet == second_pet # => true + # first_pet == third_pet # => false + # def ==(other) return false unless other.kind_of?(OpenStruct) @table == other.table! @@ -321,9 +359,11 @@ class OpenStruct https://github.com/ruby/ruby/blob/trunk/ruby_2_4/lib/ostruct.rb#L359 @table.eql?(other.table!) end - # Compute a hash-code for this OpenStruct. - # Two hashes with the same content will have the same hash code - # (and will be eql?). + # Computes a hash code for this OpenStruct. + # Two OpenStruct objects with the same content will have the same hash code + # (and will compare using #eql?). + # + # See also Object#hash. def hash @table.hash end Index: ruby_2_4/version.h =================================================================== --- ruby_2_4/version.h (revision 61363) +++ ruby_2_4/version.h (revision 61364) @@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_4/version.h#L1 #define RUBY_VERSION "2.4.4" #define RUBY_RELEASE_DATE "2017-12-20" -#define RUBY_PATCHLEVEL 211 +#define RUBY_PATCHLEVEL 212 #define RUBY_RELEASE_YEAR 2017 #define RUBY_RELEASE_MONTH 12 Index: ruby_2_4 =================================================================== --- ruby_2_4 (revision 61363) +++ ruby_2_4 (revision 61364) Property changes on: ruby_2_4 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /trunk:r57887 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/