activesupport 3.0.20 → 3.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (110) hide show
  1. data/CHANGELOG +14 -66
  2. data/README.rdoc +1 -1
  3. data/lib/active_support/backtrace_cleaner.rb +1 -1
  4. data/lib/active_support/buffered_logger.rb +4 -11
  5. data/lib/active_support/cache.rb +12 -15
  6. data/lib/active_support/cache/file_store.rb +3 -2
  7. data/lib/active_support/cache/mem_cache_store.rb +11 -3
  8. data/lib/active_support/cache/strategy/local_cache.rb +28 -23
  9. data/lib/active_support/callbacks.rb +195 -175
  10. data/lib/active_support/concern.rb +105 -35
  11. data/lib/active_support/configurable.rb +41 -2
  12. data/lib/active_support/core_ext/array/access.rb +2 -2
  13. data/lib/active_support/core_ext/array/random_access.rb +10 -7
  14. data/lib/active_support/core_ext/big_decimal/conversions.rb +0 -2
  15. data/lib/active_support/core_ext/class/attribute.rb +27 -17
  16. data/lib/active_support/core_ext/class/inheritable_attributes.rb +12 -86
  17. data/lib/active_support/core_ext/class/subclasses.rb +20 -34
  18. data/lib/active_support/core_ext/date/calculations.rb +14 -2
  19. data/lib/active_support/core_ext/date/conversions.rb +6 -0
  20. data/lib/active_support/core_ext/date_time/calculations.rb +26 -9
  21. data/lib/active_support/core_ext/date_time/conversions.rb +1 -1
  22. data/lib/active_support/core_ext/date_time/zones.rb +1 -1
  23. data/lib/active_support/core_ext/enumerable.rb +2 -5
  24. data/lib/active_support/core_ext/float/rounding.rb +1 -1
  25. data/lib/active_support/core_ext/hash.rb +1 -0
  26. data/lib/active_support/core_ext/hash/conversions.rb +23 -36
  27. data/lib/active_support/core_ext/hash/deep_dup.rb +11 -0
  28. data/lib/active_support/core_ext/hash/keys.rb +6 -4
  29. data/lib/active_support/core_ext/hash/reverse_merge.rb +9 -14
  30. data/lib/active_support/core_ext/kernel/reporting.rb +19 -0
  31. data/lib/active_support/core_ext/logger.rb +11 -38
  32. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +11 -12
  33. data/lib/active_support/core_ext/module/attr_internal.rb +13 -6
  34. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  35. data/lib/active_support/core_ext/object.rb +1 -1
  36. data/lib/active_support/core_ext/object/blank.rb +42 -9
  37. data/lib/active_support/core_ext/object/duplicable.rb +48 -9
  38. data/lib/active_support/core_ext/object/inclusion.rb +15 -0
  39. data/lib/active_support/core_ext/object/instance_variables.rb +1 -35
  40. data/lib/active_support/core_ext/object/to_param.rb +13 -8
  41. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  42. data/lib/active_support/core_ext/object/try.rb +27 -10
  43. data/lib/active_support/core_ext/object/with_options.rb +19 -5
  44. data/lib/active_support/core_ext/range.rb +1 -0
  45. data/lib/active_support/core_ext/range/cover.rb +3 -0
  46. data/lib/active_support/core_ext/string.rb +1 -0
  47. data/lib/active_support/core_ext/string/filters.rb +3 -3
  48. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  49. data/lib/active_support/core_ext/string/inquiry.rb +13 -0
  50. data/lib/active_support/core_ext/string/multibyte.rb +1 -1
  51. data/lib/active_support/core_ext/string/output_safety.rb +33 -89
  52. data/lib/active_support/core_ext/time/calculations.rb +14 -13
  53. data/lib/active_support/core_ext/time/conversions.rb +2 -24
  54. data/lib/active_support/core_ext/time/marshal.rb +0 -1
  55. data/lib/active_support/core_ext/time/zones.rb +32 -21
  56. data/lib/active_support/core_ext/uri.rb +8 -0
  57. data/lib/active_support/dependencies.rb +93 -37
  58. data/lib/active_support/deprecation.rb +2 -2
  59. data/lib/active_support/deprecation/behaviors.rb +7 -0
  60. data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
  61. data/lib/active_support/deprecation/reporting.rb +4 -0
  62. data/lib/active_support/duration.rb +4 -0
  63. data/lib/active_support/file_update_checker.rb +1 -1
  64. data/lib/active_support/file_watcher.rb +36 -0
  65. data/lib/active_support/gzip.rb +0 -1
  66. data/lib/active_support/hash_with_indifferent_access.rb +6 -4
  67. data/lib/active_support/i18n.rb +0 -1
  68. data/lib/active_support/i18n_railtie.rb +2 -2
  69. data/lib/active_support/inflector/inflections.rb +1 -1
  70. data/lib/active_support/json/decoding.rb +37 -23
  71. data/lib/active_support/json/encoding.rb +8 -3
  72. data/lib/active_support/lazy_load_hooks.rb +7 -7
  73. data/lib/active_support/log_subscriber.rb +3 -3
  74. data/lib/active_support/log_subscriber/test_helper.rb +4 -3
  75. data/lib/active_support/message_encryptor.rb +1 -1
  76. data/lib/active_support/message_verifier.rb +1 -1
  77. data/lib/active_support/multibyte/chars.rb +4 -3
  78. data/lib/active_support/multibyte/unicode.rb +1 -1
  79. data/lib/active_support/notifications.rb +9 -8
  80. data/lib/active_support/notifications/fanout.rb +3 -3
  81. data/lib/active_support/ordered_hash.rb +19 -2
  82. data/lib/active_support/ordered_options.rb +33 -3
  83. data/lib/active_support/railtie.rb +1 -1
  84. data/lib/active_support/rescuable.rb +1 -0
  85. data/lib/active_support/secure_random.rb +11 -5
  86. data/lib/active_support/test_case.rb +2 -10
  87. data/lib/active_support/testing/assertions.rb +17 -6
  88. data/lib/active_support/testing/mochaing.rb +7 -0
  89. data/lib/active_support/testing/pending.rb +27 -23
  90. data/lib/active_support/testing/setup_and_teardown.rb +8 -11
  91. data/lib/active_support/time_with_zone.rb +6 -3
  92. data/lib/active_support/version.rb +3 -3
  93. data/lib/active_support/whiny_nil.rb +1 -1
  94. data/lib/active_support/xml_mini.rb +4 -2
  95. data/lib/active_support/xml_mini/jdom.rb +9 -16
  96. data/lib/active_support/xml_mini/libxml.rb +1 -0
  97. data/lib/active_support/xml_mini/libxmlsax.rb +2 -1
  98. data/lib/active_support/xml_mini/nokogiri.rb +1 -0
  99. data/lib/active_support/xml_mini/nokogirisax.rb +1 -0
  100. data/lib/active_support/xml_mini/rexml.rb +1 -0
  101. metadata +50 -32
  102. checksums.yaml +0 -7
  103. data/lib/active_support/core_ext/cgi.rb +0 -1
  104. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -19
  105. data/lib/active_support/core_ext/object/returning.rb +0 -43
  106. data/lib/active_support/json/backends/jsongem.rb +0 -47
  107. data/lib/active_support/json/backends/okjson.rb +0 -644
  108. data/lib/active_support/json/backends/yajl.rb +0 -44
  109. data/lib/active_support/json/backends/yaml.rb +0 -19
  110. data/lib/active_support/testing/default.rb +0 -9
@@ -7,25 +7,24 @@ class Module
7
7
  # attr_accessor_with_default :age, 25
8
8
  # end
9
9
  #
10
- # some_person.age
11
- # => 25
12
- # some_person.age = 26
13
- # some_person.age
14
- # => 26
10
+ # person = Person.new
11
+ # person.age # => 25
12
+ #
13
+ # person.age = 26
14
+ # person.age # => 26
15
15
  #
16
16
  # To give attribute <tt>:element_name</tt> a dynamic default value, evaluated
17
17
  # in scope of self:
18
18
  #
19
19
  # attr_accessor_with_default(:element_name) { name.underscore }
20
20
  #
21
- def attr_accessor_with_default(sym, default = nil, &block)
22
- raise 'Default value or block required' unless !default.nil? || block
23
- define_method(sym, block_given? ? block : Proc.new { default })
21
+ def attr_accessor_with_default(sym, default = Proc.new)
22
+ define_method(sym, block_given? ? default : Proc.new { default })
24
23
  module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
25
- def #{sym}=(value) # def age=(value)
26
- class << self; attr_reader :#{sym} end # class << self; attr_reader :age end
27
- @#{sym} = value # @age = value
28
- end # end
24
+ def #{sym}=(value) # def age=(value)
25
+ class << self; attr_accessor :#{sym} end # class << self; attr_accessor :age end
26
+ @#{sym} = value # @age = value
27
+ end # end
29
28
  EVAL
30
29
  end
31
30
  end
@@ -1,16 +1,12 @@
1
1
  class Module
2
2
  # Declares an attribute reader backed by an internally-named instance variable.
3
3
  def attr_internal_reader(*attrs)
4
- attrs.each do |attr|
5
- module_eval "def #{attr}() #{attr_internal_ivar_name(attr)} end", __FILE__, __LINE__
6
- end
4
+ attrs.each {|attr_name| attr_internal_define(attr_name, :reader)}
7
5
  end
8
6
 
9
7
  # Declares an attribute writer backed by an internally-named instance variable.
10
8
  def attr_internal_writer(*attrs)
11
- attrs.each do |attr|
12
- module_eval "def #{attr}=(v) #{attr_internal_ivar_name(attr)} = v end", __FILE__, __LINE__
13
- end
9
+ attrs.each {|attr_name| attr_internal_define(attr_name, :writer)}
14
10
  end
15
11
 
16
12
  # Declares an attribute reader and writer backed by an internally-named instance
@@ -29,4 +25,15 @@ class Module
29
25
  def attr_internal_ivar_name(attr)
30
26
  Module.attr_internal_naming_format % attr
31
27
  end
28
+
29
+ def attr_internal_define(attr_name, type)
30
+ internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, '')
31
+ class_eval do # class_eval is necessary on 1.9 or else the methods a made private
32
+ # use native attr_* methods as they are faster on some Ruby implementations
33
+ send("attr_#{type}", internal_name)
34
+ end
35
+ attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
36
+ alias_method attr_name, internal_name
37
+ remove_method internal_name
38
+ end
32
39
  end
@@ -1,3 +1,5 @@
1
+ require 'active_support/deprecation'
2
+
1
3
  class Module
2
4
  # Declare that a method has been deprecated.
3
5
  # deprecate :foo
@@ -2,7 +2,7 @@ require 'active_support/core_ext/object/acts_like'
2
2
  require 'active_support/core_ext/object/blank'
3
3
  require 'active_support/core_ext/object/duplicable'
4
4
  require 'active_support/core_ext/object/try'
5
- require 'active_support/core_ext/object/returning'
5
+ require 'active_support/core_ext/object/inclusion'
6
6
 
7
7
  require 'active_support/core_ext/object/conversions'
8
8
  require 'active_support/core_ext/object/instance_variables'
@@ -13,13 +13,13 @@ class Object
13
13
  respond_to?(:empty?) ? empty? : !self
14
14
  end
15
15
 
16
- # An object is present if it's not blank.
16
+ # An object is present if it's not <tt>blank?</tt>.
17
17
  def present?
18
18
  !blank?
19
19
  end
20
20
 
21
- # Returns object if it's #present? otherwise returns nil.
22
- # object.presence is equivalent to object.present? ? object : nil.
21
+ # Returns object if it's <tt>present?</tt> otherwise returns +nil+.
22
+ # <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
23
23
  #
24
24
  # This is handy for any representation of objects where blank is the same
25
25
  # as not present at all. For example, this simplifies a common check for
@@ -37,39 +37,72 @@ class Object
37
37
  end
38
38
  end
39
39
 
40
- class NilClass #:nodoc:
40
+ class NilClass
41
+ # +nil+ is blank:
42
+ #
43
+ # nil.blank? # => true
44
+ #
41
45
  def blank?
42
46
  true
43
47
  end
44
48
  end
45
49
 
46
- class FalseClass #:nodoc:
50
+ class FalseClass
51
+ # +false+ is blank:
52
+ #
53
+ # false.blank? # => true
54
+ #
47
55
  def blank?
48
56
  true
49
57
  end
50
58
  end
51
59
 
52
- class TrueClass #:nodoc:
60
+ class TrueClass
61
+ # +true+ is not blank:
62
+ #
63
+ # true.blank? # => false
64
+ #
53
65
  def blank?
54
66
  false
55
67
  end
56
68
  end
57
69
 
58
- class Array #:nodoc:
70
+ class Array
71
+ # An array is blank if it's empty:
72
+ #
73
+ # [].blank? # => true
74
+ # [1,2,3].blank? # => false
75
+ #
59
76
  alias_method :blank?, :empty?
60
77
  end
61
78
 
62
- class Hash #:nodoc:
79
+ class Hash
80
+ # A hash is blank if it's empty:
81
+ #
82
+ # {}.blank? # => true
83
+ # {:key => 'value'}.blank? # => false
84
+ #
63
85
  alias_method :blank?, :empty?
64
86
  end
65
87
 
66
- class String #:nodoc:
88
+ class String
89
+ # A string is blank if it's empty or contains whitespaces only:
90
+ #
91
+ # "".blank? # => true
92
+ # " ".blank? # => true
93
+ # " something here ".blank? # => false
94
+ #
67
95
  def blank?
68
96
  self !~ /\S/
69
97
  end
70
98
  end
71
99
 
72
100
  class Numeric #:nodoc:
101
+ # No number is blank:
102
+ #
103
+ # 1.blank? # => false
104
+ # 0.blank? # => false
105
+ #
73
106
  def blank?
74
107
  false
75
108
  end
@@ -15,50 +15,89 @@
15
15
  # That's why we hardcode the following cases and check duplicable? instead of
16
16
  # using that rescue idiom.
17
17
  class Object
18
- # Can you safely .dup this object?
19
- # False for nil, false, true, symbols, numbers, class and module objects; true otherwise.
18
+ # Can you safely dup this object?
19
+ #
20
+ # False for +nil+, +false+, +true+, symbols, numbers, class and module objects;
21
+ # true otherwise.
20
22
  def duplicable?
21
23
  true
22
24
  end
23
25
  end
24
26
 
25
- class NilClass #:nodoc:
27
+ class NilClass
28
+ # +nil+ is not duplicable:
29
+ #
30
+ # nil.duplicable? # => false
31
+ # nil.dup # => TypeError: can't dup NilClass
32
+ #
26
33
  def duplicable?
27
34
  false
28
35
  end
29
36
  end
30
37
 
31
- class FalseClass #:nodoc:
38
+ class FalseClass
39
+ # +false+ is not duplicable:
40
+ #
41
+ # false.duplicable? # => false
42
+ # false.dup # => TypeError: can't dup FalseClass
43
+ #
32
44
  def duplicable?
33
45
  false
34
46
  end
35
47
  end
36
48
 
37
- class TrueClass #:nodoc:
49
+ class TrueClass
50
+ # +true+ is not duplicable:
51
+ #
52
+ # true.duplicable? # => false
53
+ # true.dup # => TypeError: can't dup TrueClass
54
+ #
38
55
  def duplicable?
39
56
  false
40
57
  end
41
58
  end
42
59
 
43
- class Symbol #:nodoc:
60
+ class Symbol
61
+ # Symbols are not duplicable:
62
+ #
63
+ # :my_symbol.duplicable? # => false
64
+ # :my_symbol.dup # => TypeError: can't dup Symbol
65
+ #
44
66
  def duplicable?
45
67
  false
46
68
  end
47
69
  end
48
70
 
49
- class Numeric #:nodoc:
71
+ class Numeric
72
+ # Numbers are not duplicable:
73
+ #
74
+ # 3.duplicable? # => false
75
+ # 3.dup # => TypeError: can't dup Fixnum
76
+ #
50
77
  def duplicable?
51
78
  false
52
79
  end
53
80
  end
54
81
 
55
- class Class #:nodoc:
82
+ class Class
83
+ # Classes are not duplicable:
84
+ #
85
+ # c = Class.new # => #<Class:0x10328fd80>
86
+ # c.dup # => #<Class:0x10328fd80>
87
+ #
88
+ # Note +dup+ returned the same class object.
56
89
  def duplicable?
57
90
  false
58
91
  end
59
92
  end
60
93
 
61
- class Module #:nodoc:
94
+ class Module
95
+ # Modules are not duplicable:
96
+ #
97
+ # m = Module.new # => #<Module:0x10328b6e0>
98
+ # m.dup # => #<Module:0x10328b6e0>
99
+ #
100
+ # Note +dup+ returned the same module object.
62
101
  def duplicable?
63
102
  false
64
103
  end
@@ -0,0 +1,15 @@
1
+ class Object
2
+ # Returns true if this object is included in the argument. Argument must be
3
+ # any object which responds to +#include?+. Usage:
4
+ #
5
+ # characters = ["Konata", "Kagami", "Tsukasa"]
6
+ # "Konata".in?(characters) # => true
7
+ #
8
+ # This will throw an ArgumentError if the argument doesn't respond
9
+ # to +#include?+.
10
+ def in?(another_object)
11
+ another_object.include?(self)
12
+ rescue NoMethodError
13
+ raise ArgumentError.new("The parameter passed to #in? must respond to #include?")
14
+ end
15
+ end
@@ -10,10 +10,7 @@ class Object
10
10
  #
11
11
  # C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
12
12
  def instance_values #:nodoc:
13
- instance_variables.inject({}) do |values, name|
14
- values[name.to_s[1..-1]] = instance_variable_get(name)
15
- values
16
- end
13
+ Hash[instance_variables.map { |name| [name.to_s[1..-1], instance_variable_get(name)] }]
17
14
  end
18
15
 
19
16
  # Returns an array of instance variable names including "@". They are strings
@@ -33,35 +30,4 @@ class Object
33
30
  else
34
31
  alias_method :instance_variable_names, :instance_variables
35
32
  end
36
-
37
- # Copies the instance variables of +object+ into +self+.
38
- #
39
- # Instance variable names in the +exclude+ array are ignored. If +object+
40
- # responds to <tt>protected_instance_variables</tt> the ones returned are
41
- # also ignored. For example, Rails controllers implement that method.
42
- #
43
- # In both cases strings and symbols are understood, and they have to include
44
- # the at sign.
45
- #
46
- # class C
47
- # def initialize(x, y, z)
48
- # @x, @y, @z = x, y, z
49
- # end
50
- #
51
- # def protected_instance_variables
52
- # %w(@z)
53
- # end
54
- # end
55
- #
56
- # a = C.new(0, 1, 2)
57
- # b = C.new(3, 4, 5)
58
- #
59
- # a.copy_instance_variables_from(b, [:@y])
60
- # # a is now: @x = 3, @y = 1, @z = 2
61
- def copy_instance_variables_from(object, exclude = []) #:nodoc:
62
- exclude += object.protected_instance_variables if object.respond_to? :protected_instance_variables
63
-
64
- vars = object.instance_variables.map(&:to_s) - exclude.map(&:to_s)
65
- vars.each { |name| instance_variable_set(name, object.instance_variable_get(name)) }
66
- end
67
33
  end
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  class Object
4
2
  # Alias of <tt>to_s</tt>.
5
3
  def to_param
@@ -34,14 +32,21 @@ class Array
34
32
  end
35
33
 
36
34
  class Hash
37
- # Converts a hash into a string suitable for use as a URL query string. An optional <tt>namespace</tt> can be
38
- # passed to enclose the param names (see example below). The string pairs "key=value" that conform the query
39
- # string are sorted lexicographically in ascending order.
35
+ # Returns a string representation of the receiver suitable for use as a URL
36
+ # query string:
37
+ #
38
+ # {:name => 'David', :nationality => 'Danish'}.to_param
39
+ # # => "name=David&nationality=Danish"
40
+ #
41
+ # An optional namespace can be passed to enclose the param names:
42
+ #
43
+ # {:name => 'David', :nationality => 'Danish'}.to_param('user')
44
+ # # => "user[name]=David&user[nationality]=Danish"
40
45
  #
41
- # ==== Examples
42
- # { :name => 'David', :nationality => 'Danish' }.to_param # => "name=David&nationality=Danish"
46
+ # The string pairs "key=value" that conform the query string
47
+ # are sorted lexicographically in ascending order.
43
48
  #
44
- # { :name => 'David', :nationality => 'Danish' }.to_param('user') # => "user[name]=David&user[nationality]=Danish"
49
+ # This method is also aliased as +to_query+.
45
50
  def to_param(namespace = nil)
46
51
  collect do |key, value|
47
52
  value.to_query(namespace ? "#{namespace}[#{key}]" : key)
@@ -7,7 +7,7 @@ class Object
7
7
  # Note: This method is defined as a default implementation for all Objects for Hash#to_query to work.
8
8
  def to_query(key)
9
9
  require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
10
- "#{CGI.escape(key.to_s).gsub(/%(5B|5D)/n) { [$1].pack('H*') }}=#{CGI.escape(to_param.to_s)}"
10
+ "#{CGI.escape(key.to_s)}=#{CGI.escape(to_param.to_s)}"
11
11
  end
12
12
  end
13
13
 
@@ -15,7 +15,7 @@ class Array
15
15
  # Converts an array into a string suitable for use as a URL query string,
16
16
  # using the given +key+ as the param name.
17
17
  #
18
- # ['Rails', 'coding'].to_query('hobbies') # => "hobbies[]=Rails&hobbies[]=coding"
18
+ # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
19
19
  def to_query(key)
20
20
  prefix = "#{key}[]"
21
21
  collect { |value| value.to_query(prefix) }.join '&'
@@ -5,31 +5,48 @@ class Object
5
5
  # *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
6
6
  # and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
7
7
  #
8
+ # If try is called without a method to call, it will yield any given block with the object.
9
+ #
8
10
  # ==== Examples
9
11
  #
10
- # Without try
12
+ # Without +try+
11
13
  # @person && @person.name
12
14
  # or
13
15
  # @person ? @person.name : nil
14
16
  #
15
- # With try
17
+ # With +try+
16
18
  # @person.try(:name)
17
19
  #
18
20
  # +try+ also accepts arguments and/or a block, for the method it is trying
19
21
  # Person.try(:find, 1)
20
22
  # @people.try(:collect) {|p| p.name}
23
+ #
24
+ # Without a method argument try will yield to the block unless the receiver is nil.
25
+ # @person.try { |p| "#{p.first_name} #{p.last_name}" }
21
26
  #--
22
- # This method definition below is for rdoc purposes only. The alias_method call
23
- # below overrides it as an optimization since +try+ behaves like +Object#send+,
24
- # unless called on +NilClass+.
25
- def try(method, *args, &block)
26
- send(method, *args, &block)
27
+ # +try+ behaves like +Object#send+, unless called on +NilClass+.
28
+ def try(*a, &b)
29
+ if a.empty? && block_given?
30
+ yield self
31
+ else
32
+ __send__(*a, &b)
33
+ end
27
34
  end
28
- remove_method :try
29
- alias_method :try, :__send__
30
35
  end
31
36
 
32
- class NilClass #:nodoc:
37
+ class NilClass
38
+ # Calling +try+ on +nil+ always returns +nil+.
39
+ # It becomes specially helpful when navigating through associations that may return +nil+.
40
+ #
41
+ # === Examples
42
+ #
43
+ # nil.try(:name) # => nil
44
+ #
45
+ # Without +try+
46
+ # @person && !@person.children.blank? && @person.children.first.name
47
+ #
48
+ # With +try+
49
+ # @person.try(:children).try(:first).try(:name)
33
50
  def try(*args)
34
51
  nil
35
52
  end