activesupport 1.4.4 → 2.0.0

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 (126) hide show
  1. data/CHANGELOG +263 -7
  2. data/lib/active_support.rb +9 -4
  3. data/lib/active_support/basic_object.rb +5 -0
  4. data/lib/active_support/buffered_logger.rb +107 -0
  5. data/lib/active_support/clean_logger.rb +94 -5
  6. data/lib/active_support/core_ext.rb +4 -1
  7. data/lib/active_support/core_ext/array.rb +8 -2
  8. data/lib/active_support/core_ext/array/access.rb +28 -0
  9. data/lib/active_support/core_ext/array/conversions.rb +28 -15
  10. data/lib/active_support/core_ext/array/extract_options.rb +19 -0
  11. data/lib/active_support/core_ext/array/grouping.rb +20 -7
  12. data/lib/active_support/core_ext/array/random_access.rb +12 -0
  13. data/lib/active_support/core_ext/bigdecimal.rb +1 -2
  14. data/lib/active_support/core_ext/bigdecimal/{formatting.rb → conversions.rb} +1 -2
  15. data/lib/active_support/core_ext/blank.rb +2 -8
  16. data/lib/active_support/core_ext/cgi.rb +2 -2
  17. data/lib/active_support/core_ext/class.rb +4 -3
  18. data/lib/active_support/core_ext/class/attribute_accessors.rb +1 -1
  19. data/lib/active_support/core_ext/class/delegating_attributes.rb +40 -0
  20. data/lib/active_support/core_ext/class/inheritable_attributes.rb +3 -3
  21. data/lib/active_support/core_ext/class/removal.rb +2 -2
  22. data/lib/active_support/core_ext/date.rb +5 -1
  23. data/lib/active_support/core_ext/date/behavior.rb +13 -0
  24. data/lib/active_support/core_ext/date/calculations.rb +188 -0
  25. data/lib/active_support/core_ext/date/conversions.rb +69 -13
  26. data/lib/active_support/core_ext/date_time.rb +10 -0
  27. data/lib/active_support/core_ext/date_time/calculations.rb +77 -0
  28. data/lib/active_support/core_ext/date_time/conversions.rb +54 -0
  29. data/lib/active_support/core_ext/duplicable.rb +37 -0
  30. data/lib/active_support/core_ext/enumerable.rb +1 -0
  31. data/lib/active_support/core_ext/exception.rb +2 -2
  32. data/lib/active_support/core_ext/file.rb +21 -0
  33. data/lib/active_support/core_ext/float.rb +5 -0
  34. data/lib/active_support/core_ext/float/rounding.rb +24 -0
  35. data/lib/active_support/core_ext/hash.rb +5 -5
  36. data/lib/active_support/core_ext/hash/conversions.rb +86 -34
  37. data/lib/active_support/core_ext/hash/diff.rb +8 -0
  38. data/lib/active_support/core_ext/hash/except.rb +24 -0
  39. data/lib/active_support/core_ext/hash/indifferent_access.rb +15 -2
  40. data/lib/active_support/core_ext/hash/keys.rb +10 -3
  41. data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -2
  42. data/lib/active_support/core_ext/hash/slice.rb +28 -0
  43. data/lib/active_support/core_ext/integer.rb +2 -2
  44. data/lib/active_support/core_ext/kernel.rb +5 -4
  45. data/lib/active_support/core_ext/kernel/debugger.rb +13 -0
  46. data/lib/active_support/core_ext/module.rb +8 -7
  47. data/lib/active_support/core_ext/module/aliasing.rb +17 -5
  48. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +31 -0
  49. data/lib/active_support/core_ext/module/attribute_accessors.rb +1 -1
  50. data/lib/active_support/core_ext/module/delegation.rb +21 -0
  51. data/lib/active_support/core_ext/name_error.rb +2 -2
  52. data/lib/active_support/core_ext/numeric.rb +2 -2
  53. data/lib/active_support/core_ext/numeric/time.rb +30 -11
  54. data/lib/active_support/core_ext/object.rb +3 -2
  55. data/lib/active_support/core_ext/object/extending.rb +40 -29
  56. data/lib/active_support/core_ext/object/instance_variables.rb +22 -0
  57. data/lib/active_support/core_ext/object/misc.rb +29 -4
  58. data/lib/active_support/core_ext/pathname.rb +1 -1
  59. data/lib/active_support/core_ext/range.rb +7 -1
  60. data/lib/active_support/core_ext/range/blockless_step.rb +22 -0
  61. data/lib/active_support/core_ext/range/conversions.rb +8 -6
  62. data/lib/active_support/core_ext/range/include_range.rb +22 -0
  63. data/lib/active_support/core_ext/range/overlaps.rb +12 -0
  64. data/lib/active_support/core_ext/string.rb +10 -7
  65. data/lib/active_support/core_ext/string/conversions.rb +5 -1
  66. data/lib/active_support/core_ext/string/unicode.rb +2 -2
  67. data/lib/active_support/core_ext/string/xchar.rb +11 -0
  68. data/lib/active_support/core_ext/symbol.rb +12 -10
  69. data/lib/active_support/core_ext/test.rb +1 -0
  70. data/lib/active_support/core_ext/test/unit/assertions.rb +62 -0
  71. data/lib/active_support/core_ext/time.rb +4 -2
  72. data/lib/active_support/core_ext/time/behavior.rb +13 -0
  73. data/lib/active_support/core_ext/time/calculations.rb +87 -54
  74. data/lib/active_support/core_ext/time/conversions.rb +71 -10
  75. data/lib/active_support/dependencies.rb +25 -24
  76. data/lib/active_support/deprecation.rb +4 -2
  77. data/lib/active_support/duration.rb +86 -0
  78. data/lib/active_support/inflections.rb +2 -1
  79. data/lib/active_support/inflector.rb +13 -6
  80. data/lib/active_support/json.rb +22 -39
  81. data/lib/active_support/json/decoding.rb +60 -0
  82. data/lib/active_support/json/encoders/date.rb +5 -0
  83. data/lib/active_support/json/encoders/date_time.rb +5 -0
  84. data/lib/active_support/json/encoders/enumerable.rb +12 -0
  85. data/lib/active_support/json/encoders/false_class.rb +5 -0
  86. data/lib/active_support/json/encoders/hash.rb +50 -0
  87. data/lib/active_support/json/encoders/nil_class.rb +5 -0
  88. data/lib/active_support/json/encoders/numeric.rb +5 -0
  89. data/lib/active_support/json/encoders/object.rb +6 -0
  90. data/lib/active_support/json/encoders/regexp.rb +5 -0
  91. data/lib/active_support/json/encoders/string.rb +30 -0
  92. data/lib/active_support/json/encoders/symbol.rb +5 -0
  93. data/lib/active_support/json/encoders/time.rb +5 -0
  94. data/lib/active_support/json/encoders/true_class.rb +5 -0
  95. data/lib/active_support/json/encoding.rb +38 -0
  96. data/lib/active_support/json/variable.rb +10 -0
  97. data/lib/active_support/multibyte.rb +7 -5
  98. data/lib/active_support/multibyte/chars.rb +6 -0
  99. data/lib/active_support/multibyte/handlers/utf8_handler.rb +115 -5
  100. data/lib/active_support/option_merger.rb +7 -7
  101. data/lib/active_support/ordered_options.rb +22 -17
  102. data/lib/active_support/test_case.rb +5 -0
  103. data/lib/active_support/testing.rb +1 -0
  104. data/lib/active_support/testing/default.rb +12 -0
  105. data/lib/active_support/values/time_zone.rb +3 -3
  106. data/lib/active_support/vendor.rb +14 -0
  107. data/lib/active_support/vendor/builder-2.1.2/blankslate.rb +113 -0
  108. data/lib/active_support/vendor/{builder.rb → builder-2.1.2/builder.rb} +0 -0
  109. data/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb +20 -0
  110. data/lib/active_support/vendor/builder-2.1.2/builder/css.rb +250 -0
  111. data/lib/active_support/vendor/{builder → builder-2.1.2/builder}/xchar.rb +11 -8
  112. data/lib/active_support/vendor/{builder → builder-2.1.2/builder}/xmlbase.rb +38 -44
  113. data/lib/active_support/vendor/{builder → builder-2.1.2/builder}/xmlevents.rb +1 -1
  114. data/lib/active_support/vendor/{builder → builder-2.1.2/builder}/xmlmarkup.rb +40 -39
  115. data/lib/active_support/vendor/{xml_simple.rb → xml-simple-1.0.11/xmlsimple.rb} +3 -3
  116. data/lib/active_support/version.rb +3 -3
  117. data/lib/active_support/whiny_nil.rb +12 -12
  118. data/lib/activesupport.rb +1 -0
  119. metadata +69 -17
  120. data/lib/active_support/binding_of_caller.rb +0 -84
  121. data/lib/active_support/breakpoint.rb +0 -528
  122. data/lib/active_support/caching_tools.rb +0 -62
  123. data/lib/active_support/json/encoders.rb +0 -25
  124. data/lib/active_support/json/encoders/core.rb +0 -70
  125. data/lib/active_support/reloadable.rb +0 -60
  126. data/lib/active_support/vendor/builder/blankslate.rb +0 -63
@@ -1,10 +1,23 @@
1
1
  require 'logger'
2
- require File.dirname(__FILE__) + '/core_ext/class/attribute_accessors'
2
+ require 'active_support/core_ext/class/attribute_accessors'
3
3
 
4
- class Logger #:nodoc:
4
+ # Extensions to the built in Ruby logger.
5
+ #
6
+ # If you want to use the default log formatter as defined in the Ruby core, then you
7
+ # will need to set the formatter for the logger as in:
8
+ #
9
+ # logger.formatter = Formatter.new
10
+ #
11
+ # You can then specify the datetime format, for example:
12
+ #
13
+ # logger.datetime_format = "%Y-%m-%d"
14
+ #
15
+ # Note: This logger is deprecated in favor of ActiveSupport::BufferedLogger
16
+ class Logger
17
+ # Set to false to disable the silencer
5
18
  cattr_accessor :silencer
6
19
  self.silencer = true
7
-
20
+
8
21
  # Silences the logger for the duration of the block.
9
22
  def silence(temporary_level = Logger::ERROR)
10
23
  if silencer
@@ -18,6 +31,73 @@ class Logger #:nodoc:
18
31
  yield self
19
32
  end
20
33
  end
34
+
35
+ alias :old_datetime_format= :datetime_format=
36
+ # Logging date-time format (string passed to +strftime+). Ignored if the formatter
37
+ # does not respond to datetime_format=.
38
+ def datetime_format=(datetime_format)
39
+ formatter.datetime_format = datetime_format if formatter.respond_to?(:datetime_format=)
40
+ end
41
+
42
+ alias :old_datetime_format :datetime_format
43
+ # Get the logging datetime format. Returns nil if the formatter does not support
44
+ # datetime formatting.
45
+ def datetime_format
46
+ formatter.datetime_format if formatter.respond_to?(:datetime_format)
47
+ end
48
+
49
+ alias :old_formatter :formatter if method_defined?(:formatter)
50
+ # Get the current formatter. The default formatter is a SimpleFormatter which only
51
+ # displays the log message
52
+ def formatter
53
+ @formatter ||= SimpleFormatter.new
54
+ end
55
+
56
+ unless const_defined? :Formatter
57
+ class Formatter
58
+ Format = "%s, [%s#%d] %5s -- %s: %s\n"
59
+
60
+ attr_accessor :datetime_format
61
+
62
+ def initialize
63
+ @datetime_format = nil
64
+ end
65
+
66
+ def call(severity, time, progname, msg)
67
+ Format % [severity[0..0], format_datetime(time), $$, severity, progname,
68
+ msg2str(msg)]
69
+ end
70
+
71
+ private
72
+ def format_datetime(time)
73
+ if @datetime_format.nil?
74
+ time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % time.usec
75
+ else
76
+ time.strftime(@datetime_format)
77
+ end
78
+ end
79
+
80
+ def msg2str(msg)
81
+ case msg
82
+ when ::String
83
+ msg
84
+ when ::Exception
85
+ "#{ msg.message } (#{ msg.class })\n" <<
86
+ (msg.backtrace || []).join("\n")
87
+ else
88
+ msg.inspect
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ # Simple formatter which only displays the message.
95
+ class SimpleFormatter < Logger::Formatter
96
+ # This method is invoked when a log event occurs
97
+ def call(severity, timestamp, progname, msg)
98
+ "#{String === msg ? msg : msg.inspect}\n"
99
+ end
100
+ end
21
101
 
22
102
  private
23
103
  alias old_format_message format_message
@@ -28,11 +108,20 @@ class Logger #:nodoc:
28
108
  # with Logger from 1.8.3 and vice versa.
29
109
  if method_defined?(:formatter=)
30
110
  def format_message(severity, timestamp, progname, msg)
31
- "#{msg}\n"
111
+ formatter.call(severity, timestamp, progname, msg)
32
112
  end
33
113
  else
34
114
  def format_message(severity, timestamp, msg, progname)
35
- "#{msg}\n"
115
+ formatter.call(severity, timestamp, progname, msg)
36
116
  end
117
+
118
+ attr_writer :formatter
119
+ public :formatter=
120
+
121
+ alias old_format_datetime format_datetime
122
+ def format_datetime(datetime) datetime end
123
+
124
+ alias old_msg2str msg2str
125
+ def msg2str(msg) msg end
37
126
  end
38
127
  end
@@ -1 +1,4 @@
1
- Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].each { |file| require(file) }
1
+ Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].sort.each do |path|
2
+ filename = File.basename(path)
3
+ require "active_support/core_ext/#{filename}"
4
+ end
@@ -1,7 +1,13 @@
1
- require File.dirname(__FILE__) + '/array/conversions'
2
- require File.dirname(__FILE__) + '/array/grouping'
1
+ require 'active_support/core_ext/array/access'
2
+ require 'active_support/core_ext/array/conversions'
3
+ require 'active_support/core_ext/array/extract_options'
4
+ require 'active_support/core_ext/array/grouping'
5
+ require 'active_support/core_ext/array/random_access'
3
6
 
4
7
  class Array #:nodoc:
8
+ include ActiveSupport::CoreExtensions::Array::Access
5
9
  include ActiveSupport::CoreExtensions::Array::Conversions
10
+ include ActiveSupport::CoreExtensions::Array::ExtractOptions
6
11
  include ActiveSupport::CoreExtensions::Array::Grouping
12
+ include ActiveSupport::CoreExtensions::Array::RandomAccess
7
13
  end
@@ -0,0 +1,28 @@
1
+ module ActiveSupport #:nodoc:
2
+ module CoreExtensions #:nodoc:
3
+ module Array #:nodoc:
4
+ # Makes it easier to access parts of an array.
5
+ module Access
6
+ # Returns the remaining of the array from the +position+.
7
+ #
8
+ # Examples:
9
+ # %w( a b c d ).from(0) # => %w( a b c d )
10
+ # %w( a b c d ).from(2) # => %w( c d )
11
+ # %w( a b c d ).from(10) # => nil
12
+ def from(position)
13
+ self[position..-1]
14
+ end
15
+
16
+ # Returns the beginning of the array up to the +position+.
17
+ #
18
+ # Examples:
19
+ # %w( a b c d ).to(0) # => %w( a )
20
+ # %w( a b c d ).to(2) # => %w( a b c )
21
+ # %w( a b c d ).to(10) # => %w( a b c d )
22
+ def to(position)
23
+ self[0..position]
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,23 +1,26 @@
1
+ require 'builder'
2
+
1
3
  module ActiveSupport #:nodoc:
2
4
  module CoreExtensions #:nodoc:
3
5
  module Array #:nodoc:
4
6
  module Conversions
5
- # Converts the array to comma-seperated sentence where the last element is joined by the connector word. Options:
6
- # * <tt>:connector</tt>: The word used to join the last element in arrays with two or more elements (default: "and")
7
- # * <tt>:skip_last_comma</tt>: Set to true to return "a, b and c" instead of "a, b, and c".
7
+ # Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options:
8
+ # * <tt>:connector</tt> - The word used to join the last element in arrays with two or more elements (default: "and")
9
+ # * <tt>:skip_last_comma</tt> - Set to true to return "a, b and c" instead of "a, b, and c".
8
10
  def to_sentence(options = {})
9
11
  options.assert_valid_keys(:connector, :skip_last_comma)
10
12
  options.reverse_merge! :connector => 'and', :skip_last_comma => false
11
-
13
+ options[:connector] = "#{options[:connector]} " unless options[:connector].nil? || options[:connector].strip == ''
14
+
12
15
  case length
13
- when 0
14
- ""
16
+ when 0
17
+ ""
15
18
  when 1
16
19
  self[0]
17
20
  when 2
18
- "#{self[0]} #{options[:connector]} #{self[1]}"
21
+ "#{self[0]} #{options[:connector]}#{self[1]}"
19
22
  else
20
- "#{self[0...-1].join(', ')}#{options[:skip_last_comma] ? '' : ','} #{options[:connector]} #{self[-1]}"
23
+ "#{self[0...-1].join(', ')}#{options[:skip_last_comma] ? '' : ','} #{options[:connector]}#{self[-1]}"
21
24
  end
22
25
  end
23
26
 
@@ -25,12 +28,14 @@ module ActiveSupport #:nodoc:
25
28
  def to_param
26
29
  join '/'
27
30
  end
28
-
29
- def self.included(klass) #:nodoc:
30
- klass.send(:alias_method, :to_default_s, :to_s)
31
- klass.send(:alias_method, :to_s, :to_formatted_s)
31
+
32
+ def self.included(base) #:nodoc:
33
+ base.class_eval do
34
+ alias_method :to_default_s, :to_s
35
+ alias_method :to_s, :to_formatted_s
36
+ end
32
37
  end
33
-
38
+
34
39
  def to_formatted_s(format = :default)
35
40
  case format
36
41
  when :db
@@ -43,7 +48,7 @@ module ActiveSupport #:nodoc:
43
48
  to_default_s
44
49
  end
45
50
  end
46
-
51
+
47
52
  def to_xml(options = {})
48
53
  raise "Not all elements respond to to_xml" unless all? { |e| e.respond_to? :to_xml }
49
54
 
@@ -63,7 +68,15 @@ module ActiveSupport #:nodoc:
63
68
 
64
69
  opts = options.merge({ :root => children })
65
70
 
66
- options[:builder].tag!(root) { each { |e| e.to_xml(opts.merge!({ :skip_instruct => true })) } }
71
+ xml = options[:builder]
72
+ if empty?
73
+ xml.tag!(root, options[:skip_types] ? {} : {:type => "array"})
74
+ else
75
+ xml.tag!(root, options[:skip_types] ? {} : {:type => "array"}) {
76
+ yield xml if block_given?
77
+ each { |e| e.to_xml(opts.merge!({ :skip_instruct => true })) }
78
+ }
79
+ end
67
80
  end
68
81
 
69
82
  end
@@ -0,0 +1,19 @@
1
+ module ActiveSupport #:nodoc:
2
+ module CoreExtensions #:nodoc:
3
+ module Array #:nodoc:
4
+ module ExtractOptions
5
+ # Extract options from a set of arguments. Removes and returns the last element in the array if it's a hash, otherwise returns a blank hash.
6
+ #
7
+ # def options(*args)
8
+ # args.extract_options!
9
+ # end
10
+ #
11
+ # options(1, 2) # => {}
12
+ # options(1, 2, :a => :b) # => {:a=>:b}
13
+ def extract_options!
14
+ last.is_a?(::Hash) ? pop : {}
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,5 @@
1
+ require 'enumerator'
2
+
1
3
  module ActiveSupport #:nodoc:
2
4
  module CoreExtensions #:nodoc:
3
5
  module Array #:nodoc:
@@ -21,14 +23,23 @@ module ActiveSupport #:nodoc:
21
23
  # ["1", "2"]
22
24
  # ["3"]
23
25
  def in_groups_of(number, fill_with = nil, &block)
24
- require 'enumerator'
25
- collection = dup
26
- collection << fill_with until collection.size.modulo(number).zero? unless fill_with == false
27
- grouped_collection = [] unless block_given?
28
- collection.each_slice(number) do |group|
29
- block_given? ? yield(group) : grouped_collection << group
26
+ if fill_with == false
27
+ collection = self
28
+ else
29
+ # size % number gives how many extra we have;
30
+ # subtracting from number gives how many to add;
31
+ # modulo number ensures we don't add group of just fill.
32
+ padding = (number - size % number) % number
33
+ collection = dup.concat([fill_with] * padding)
34
+ end
35
+
36
+ if block_given?
37
+ collection.each_slice(number, &block)
38
+ else
39
+ returning [] do |groups|
40
+ collection.each_slice(number) { |group| groups << group }
41
+ end
30
42
  end
31
- grouped_collection unless block_given?
32
43
  end
33
44
 
34
45
  # Divide the array into one or more subarrays based on a delimiting +value+
@@ -40,12 +51,14 @@ module ActiveSupport #:nodoc:
40
51
  # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
41
52
  def split(value = nil, &block)
42
53
  block ||= Proc.new { |e| e == value }
54
+
43
55
  inject([[]]) do |results, element|
44
56
  if block.call(element)
45
57
  results << []
46
58
  else
47
59
  results.last << element
48
60
  end
61
+
49
62
  results
50
63
  end
51
64
  end
@@ -0,0 +1,12 @@
1
+ module ActiveSupport #:nodoc:
2
+ module CoreExtensions #:nodoc:
3
+ module Array #:nodoc:
4
+ module RandomAccess
5
+ # Return a random element from the array.
6
+ def rand
7
+ self[Kernel.rand(length)]
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,3 +1,2 @@
1
1
  require 'bigdecimal'
2
-
3
- require File.dirname(__FILE__) + '/bigdecimal/formatting.rb'
2
+ require 'active_support/core_ext/bigdecimal/conversions'
@@ -1,7 +1,6 @@
1
1
  class BigDecimal #:nodoc:
2
-
3
2
  alias :_original_to_s :to_s
4
3
  def to_s(format="F")
5
4
  _original_to_s(format)
6
5
  end
7
- end
6
+ end
@@ -7,13 +7,7 @@ class Object
7
7
  # to
8
8
  # if !address.blank?
9
9
  def blank?
10
- if respond_to?(:empty?) && respond_to?(:strip)
11
- empty? or strip.empty?
12
- elsif respond_to?(:empty?)
13
- empty?
14
- else
15
- !self
16
- end
10
+ respond_to?(:empty?) ? empty? : !self
17
11
  end
18
12
  end
19
13
 
@@ -45,7 +39,7 @@ end
45
39
 
46
40
  class String #:nodoc:
47
41
  def blank?
48
- empty? || strip.empty?
42
+ self !~ /\S/
49
43
  end
50
44
  end
51
45
 
@@ -1,5 +1,5 @@
1
- require File.dirname(__FILE__) + '/cgi/escape_skipping_slashes'
1
+ require 'active_support/core_ext/cgi/escape_skipping_slashes'
2
2
 
3
3
  class CGI #:nodoc:
4
- extend(ActiveSupport::CoreExtensions::CGI::EscapeSkippingSlashes)
4
+ extend ActiveSupport::CoreExtensions::CGI::EscapeSkippingSlashes
5
5
  end
@@ -1,3 +1,4 @@
1
- require File.dirname(__FILE__) + '/class/attribute_accessors'
2
- require File.dirname(__FILE__) + '/class/inheritable_attributes'
3
- require File.dirname(__FILE__) + '/class/removal'
1
+ require 'active_support/core_ext/class/attribute_accessors'
2
+ require 'active_support/core_ext/class/inheritable_attributes'
3
+ require 'active_support/core_ext/class/removal'
4
+ require 'active_support/core_ext/class/delegating_attributes'
@@ -21,7 +21,7 @@ class Class # :nodoc:
21
21
  end
22
22
 
23
23
  def cattr_writer(*syms)
24
- options = syms.last.is_a?(Hash) ? syms.pop : {}
24
+ options = syms.extract_options!
25
25
  syms.flatten.each do |sym|
26
26
  class_eval(<<-EOS, __FILE__, __LINE__)
27
27
  unless defined? @@#{sym}
@@ -0,0 +1,40 @@
1
+ # These class attributes behave something like the class
2
+ # inheritable accessors. But instead of copying the hash over at
3
+ # the time the subclass is first defined, the accessors simply
4
+ # delegate to their superclass unless they have been given a
5
+ # specific value. This stops the strange situation where values
6
+ # set after class definition don't get applied to subclasses.
7
+ class Class
8
+ def superclass_delegating_reader(*names)
9
+ class_name_to_stop_searching_on = self.superclass.name.blank? ? "Object" : self.superclass.name
10
+ names.each do |name|
11
+ class_eval <<-EOS
12
+ def self.#{name}
13
+ if defined?(@#{name})
14
+ @#{name}
15
+ elsif superclass < #{class_name_to_stop_searching_on} && superclass.respond_to?(:#{name})
16
+ superclass.#{name}
17
+ end
18
+ end
19
+ def #{name}
20
+ self.class.#{name}
21
+ end
22
+ EOS
23
+ end
24
+ end
25
+
26
+ def superclass_delegating_writer(*names)
27
+ names.each do |name|
28
+ class_eval <<-EOS
29
+ def self.#{name}=(value)
30
+ @#{name} = value
31
+ end
32
+ EOS
33
+ end
34
+ end
35
+
36
+ def superclass_delegating_accessor(*names)
37
+ superclass_delegating_reader(*names)
38
+ superclass_delegating_writer(*names)
39
+ end
40
+ end