activeobject 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/CHANGE +10 -0
  2. data/Interface_desc +21 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README +72 -0
  5. data/Rakefile.rb +9 -0
  6. data/active-object.gemspec +50 -0
  7. data/examples/account.rb +69 -0
  8. data/examples/data.tch +0 -0
  9. data/examples/light_cloud.yml +18 -0
  10. data/examples/test.rb +3 -0
  11. data/examples/user.rb +112 -0
  12. data/init.rb +4 -0
  13. data/lib/active-object.rb +23 -0
  14. data/lib/active_object/adapters/light_cloud.rb +40 -0
  15. data/lib/active_object/adapters/tokyo_cabinet.rb +48 -0
  16. data/lib/active_object/adapters/tokyo_tyrant.rb +14 -0
  17. data/lib/active_object/associations.rb +200 -0
  18. data/lib/active_object/base.rb +415 -0
  19. data/lib/active_object/callbacks.rb +180 -0
  20. data/lib/active_object/observer.rb +180 -0
  21. data/lib/active_object/serialization.rb +99 -0
  22. data/lib/active_object/serializers/json_serializer.rb +75 -0
  23. data/lib/active_object/serializers/xml_serializer.rb +325 -0
  24. data/lib/active_object/validations.rb +687 -0
  25. data/lib/active_support/callbacks.rb +303 -0
  26. data/lib/active_support/core_ext/array/access.rb +53 -0
  27. data/lib/active_support/core_ext/array/conversions.rb +183 -0
  28. data/lib/active_support/core_ext/array/extract_options.rb +20 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +106 -0
  30. data/lib/active_support/core_ext/array/random_access.rb +12 -0
  31. data/lib/active_support/core_ext/array.rb +13 -0
  32. data/lib/active_support/core_ext/blank.rb +58 -0
  33. data/lib/active_support/core_ext/class/attribute_accessors.rb +54 -0
  34. data/lib/active_support/core_ext/class/inheritable_attributes.rb +140 -0
  35. data/lib/active_support/core_ext/class/removal.rb +50 -0
  36. data/lib/active_support/core_ext/class.rb +3 -0
  37. data/lib/active_support/core_ext/duplicable.rb +43 -0
  38. data/lib/active_support/core_ext/enumerable.rb +72 -0
  39. data/lib/active_support/core_ext/hash/conversions.rb +259 -0
  40. data/lib/active_support/core_ext/hash/keys.rb +52 -0
  41. data/lib/active_support/core_ext/hash.rb +8 -0
  42. data/lib/active_support/core_ext/module/aliasing.rb +74 -0
  43. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +31 -0
  44. data/lib/active_support/core_ext/module/attribute_accessors.rb +58 -0
  45. data/lib/active_support/core_ext/module.rb +16 -0
  46. data/lib/active_support/core_ext/object/conversions.rb +14 -0
  47. data/lib/active_support/core_ext/object/extending.rb +80 -0
  48. data/lib/active_support/core_ext/object/instance_variables.rb +74 -0
  49. data/lib/active_support/core_ext/object/metaclass.rb +13 -0
  50. data/lib/active_support/core_ext/object/misc.rb +43 -0
  51. data/lib/active_support/core_ext/object.rb +5 -0
  52. data/lib/active_support/core_ext/string/inflections.rb +167 -0
  53. data/lib/active_support/core_ext/string.rb +7 -0
  54. data/lib/active_support/core_ext.rb +4 -0
  55. data/lib/active_support/inflections.rb +55 -0
  56. data/lib/active_support/inflector.rb +348 -0
  57. data/lib/active_support/vendor/builder-2.1.2/blankslate.rb +113 -0
  58. data/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb +20 -0
  59. data/lib/active_support/vendor/builder-2.1.2/builder/css.rb +250 -0
  60. data/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb +115 -0
  61. data/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb +139 -0
  62. data/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb +63 -0
  63. data/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb +328 -0
  64. data/lib/active_support/vendor/builder-2.1.2/builder.rb +13 -0
  65. data/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb +1021 -0
  66. data/lib/active_support/vendor.rb +14 -0
  67. data/lib/active_support.rb +6 -0
  68. data/spec/case/association_test.rb +97 -0
  69. data/spec/case/base_test.rb +74 -0
  70. data/spec/case/callbacks_observers_test.rb +38 -0
  71. data/spec/case/callbacks_test.rb +424 -0
  72. data/spec/case/serialization_test.rb +87 -0
  73. data/spec/case/validations_test.rb +1482 -0
  74. data/spec/data.tch +0 -0
  75. data/spec/helper.rb +15 -0
  76. data/spec/light_cloud.yml +18 -0
  77. data/spec/model/account.rb +4 -0
  78. data/spec/model/topic.rb +26 -0
  79. data/spec/model/user.rb +8 -0
  80. metadata +173 -0
@@ -0,0 +1,55 @@
1
+ module ActiveSupport
2
+ Inflector.inflections do |inflect|
3
+ inflect.plural(/$/, 's')
4
+ inflect.plural(/s$/i, 's')
5
+ inflect.plural(/(ax|test)is$/i, '\1es')
6
+ inflect.plural(/(octop|vir)us$/i, '\1i')
7
+ inflect.plural(/(alias|status)$/i, '\1es')
8
+ inflect.plural(/(bu)s$/i, '\1ses')
9
+ inflect.plural(/(buffal|tomat)o$/i, '\1oes')
10
+ inflect.plural(/([ti])um$/i, '\1a')
11
+ inflect.plural(/sis$/i, 'ses')
12
+ inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
13
+ inflect.plural(/(hive)$/i, '\1s')
14
+ inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
15
+ inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
16
+ inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
17
+ inflect.plural(/([m|l])ouse$/i, '\1ice')
18
+ inflect.plural(/^(ox)$/i, '\1en')
19
+ inflect.plural(/(quiz)$/i, '\1zes')
20
+
21
+ inflect.singular(/s$/i, '')
22
+ inflect.singular(/(n)ews$/i, '\1ews')
23
+ inflect.singular(/([ti])a$/i, '\1um')
24
+ inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
25
+ inflect.singular(/(^analy)ses$/i, '\1sis')
26
+ inflect.singular(/([^f])ves$/i, '\1fe')
27
+ inflect.singular(/(hive)s$/i, '\1')
28
+ inflect.singular(/(tive)s$/i, '\1')
29
+ inflect.singular(/([lr])ves$/i, '\1f')
30
+ inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
31
+ inflect.singular(/(s)eries$/i, '\1eries')
32
+ inflect.singular(/(m)ovies$/i, '\1ovie')
33
+ inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
34
+ inflect.singular(/([m|l])ice$/i, '\1ouse')
35
+ inflect.singular(/(bus)es$/i, '\1')
36
+ inflect.singular(/(o)es$/i, '\1')
37
+ inflect.singular(/(shoe)s$/i, '\1')
38
+ inflect.singular(/(cris|ax|test)es$/i, '\1is')
39
+ inflect.singular(/(octop|vir)i$/i, '\1us')
40
+ inflect.singular(/(alias|status)es$/i, '\1')
41
+ inflect.singular(/^(ox)en/i, '\1')
42
+ inflect.singular(/(vert|ind)ices$/i, '\1ex')
43
+ inflect.singular(/(matr)ices$/i, '\1ix')
44
+ inflect.singular(/(quiz)zes$/i, '\1')
45
+
46
+ inflect.irregular('person', 'people')
47
+ inflect.irregular('man', 'men')
48
+ inflect.irregular('child', 'children')
49
+ inflect.irregular('sex', 'sexes')
50
+ inflect.irregular('move', 'moves')
51
+ inflect.irregular('cow', 'kine')
52
+
53
+ inflect.uncountable(%w(equipment information rice money species series fish sheep))
54
+ end
55
+ end
@@ -0,0 +1,348 @@
1
+ # encoding: utf-8
2
+ require 'singleton'
3
+ require 'iconv'
4
+
5
+ module ActiveSupport
6
+ # The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
7
+ # and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept
8
+ # in inflections.rb.
9
+ #
10
+ module Inflector
11
+ extend self
12
+
13
+ # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
14
+ # inflection rules. Examples:
15
+ #
16
+ # ActiveSupport::Inflector.inflections do |inflect|
17
+ # inflect.plural /^(ox)$/i, '\1\2en'
18
+ # inflect.singular /^(ox)en/i, '\1'
19
+ #
20
+ # inflect.irregular 'octopus', 'octopi'
21
+ #
22
+ # inflect.uncountable "equipment"
23
+ # end
24
+ #
25
+ # New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
26
+ # pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
27
+ # already have been loaded.
28
+ class Inflections
29
+ include Singleton
30
+
31
+ attr_reader :plurals, :singulars, :uncountables, :humans
32
+
33
+ def initialize
34
+ @plurals, @singulars, @uncountables, @humans = [], [], [], []
35
+ end
36
+
37
+ # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
38
+ # The replacement should always be a string that may include references to the matched data from the rule.
39
+ def plural(rule, replacement)
40
+ @uncountables.delete(rule) if rule.is_a?(String)
41
+ @uncountables.delete(replacement)
42
+ @plurals.insert(0, [rule, replacement])
43
+ end
44
+
45
+ # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
46
+ # The replacement should always be a string that may include references to the matched data from the rule.
47
+ def singular(rule, replacement)
48
+ @uncountables.delete(rule) if rule.is_a?(String)
49
+ @uncountables.delete(replacement)
50
+ @singulars.insert(0, [rule, replacement])
51
+ end
52
+
53
+ # Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
54
+ # for strings, not regular expressions. You simply pass the irregular in singular and plural form.
55
+ #
56
+ # Examples:
57
+ # irregular 'octopus', 'octopi'
58
+ # irregular 'person', 'people'
59
+ def irregular(singular, plural)
60
+ @uncountables.delete(singular)
61
+ @uncountables.delete(plural)
62
+ if singular[0,1].upcase == plural[0,1].upcase
63
+ plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
64
+ singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
65
+ else
66
+ plural(Regexp.new("#{singular[0,1].upcase}(?i)#{singular[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
67
+ plural(Regexp.new("#{singular[0,1].downcase}(?i)#{singular[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
68
+ singular(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), singular[0,1].upcase + singular[1..-1])
69
+ singular(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), singular[0,1].downcase + singular[1..-1])
70
+ end
71
+ end
72
+
73
+ # Add uncountable words that shouldn't be attempted inflected.
74
+ #
75
+ # Examples:
76
+ # uncountable "money"
77
+ # uncountable "money", "information"
78
+ # uncountable %w( money information rice )
79
+ def uncountable(*words)
80
+ (@uncountables << words).flatten!
81
+ end
82
+
83
+ # Specifies a humanized form of a string by a regular expression rule or by a string mapping.
84
+ # When using a regular expression based replacement, the normal humanize formatting is called after the replacement.
85
+ # When a string is used, the human form should be specified as desired (example: 'The name', not 'the_name')
86
+ #
87
+ # Examples:
88
+ # human /_cnt$/i, '\1_count'
89
+ # human "legacy_col_person_name", "Name"
90
+ def human(rule, replacement)
91
+ @humans.insert(0, [rule, replacement])
92
+ end
93
+
94
+ # Clears the loaded inflections within a given scope (default is <tt>:all</tt>).
95
+ # Give the scope as a symbol of the inflection type, the options are: <tt>:plurals</tt>,
96
+ # <tt>:singulars</tt>, <tt>:uncountables</tt>, <tt>:humans</tt>.
97
+ #
98
+ # Examples:
99
+ # clear :all
100
+ # clear :plurals
101
+ def clear(scope = :all)
102
+ case scope
103
+ when :all
104
+ @plurals, @singulars, @uncountables = [], [], []
105
+ else
106
+ instance_variable_set "@#{scope}", []
107
+ end
108
+ end
109
+ end
110
+
111
+ # Yields a singleton instance of Inflector::Inflections so you can specify additional
112
+ # inflector rules.
113
+ #
114
+ # Example:
115
+ # ActiveSupport::Inflector.inflections do |inflect|
116
+ # inflect.uncountable "rails"
117
+ # end
118
+ def inflections
119
+ if block_given?
120
+ yield Inflections.instance
121
+ else
122
+ Inflections.instance
123
+ end
124
+ end
125
+
126
+ # Returns the plural form of the word in the string.
127
+ #
128
+ # Examples:
129
+ # "post".pluralize # => "posts"
130
+ # "octopus".pluralize # => "octopi"
131
+ # "sheep".pluralize # => "sheep"
132
+ # "words".pluralize # => "words"
133
+ # "CamelOctopus".pluralize # => "CamelOctopi"
134
+ def pluralize(word)
135
+ result = word.to_s.dup
136
+
137
+ if word.empty? || inflections.uncountables.include?(result.downcase)
138
+ result
139
+ else
140
+ inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
141
+ result
142
+ end
143
+ end
144
+
145
+ # The reverse of +pluralize+, returns the singular form of a word in a string.
146
+ #
147
+ # Examples:
148
+ # "posts".singularize # => "post"
149
+ # "octopi".singularize # => "octopus"
150
+ # "sheep".singluarize # => "sheep"
151
+ # "word".singularize # => "word"
152
+ # "CamelOctopi".singularize # => "CamelOctopus"
153
+ def singularize(word)
154
+ result = word.to_s.dup
155
+
156
+ if inflections.uncountables.include?(result.downcase)
157
+ result
158
+ else
159
+ inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
160
+ result
161
+ end
162
+ end
163
+
164
+ # By default, +camelize+ converts strings to UpperCamelCase. If the argument to +camelize+
165
+ # is set to <tt>:lower</tt> then +camelize+ produces lowerCamelCase.
166
+ #
167
+ # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
168
+ #
169
+ # Examples:
170
+ # "active_record".camelize # => "ActiveRecord"
171
+ # "active_record".camelize(:lower) # => "activeRecord"
172
+ # "active_record/errors".camelize # => "ActiveRecord::Errors"
173
+ # "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
174
+ def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
175
+ if first_letter_in_uppercase
176
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
177
+ else
178
+ lower_case_and_underscored_word.first.downcase + camelize(lower_case_and_underscored_word)[1..-1]
179
+ end
180
+ end
181
+
182
+ # Capitalizes all the words and replaces some characters in the string to create
183
+ # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
184
+ # used in the Rails internals.
185
+ #
186
+ # +titleize+ is also aliased as as +titlecase+.
187
+ #
188
+ # Examples:
189
+ # "man from the boondocks".titleize # => "Man From The Boondocks"
190
+ # "x-men: the last stand".titleize # => "X Men: The Last Stand"
191
+ def titleize(word)
192
+ humanize(underscore(word)).gsub(/\b('?[a-z])/) { $1.capitalize }
193
+ end
194
+
195
+ # The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
196
+ #
197
+ # Changes '::' to '/' to convert namespaces to paths.
198
+ #
199
+ # Examples:
200
+ # "ActiveRecord".underscore # => "active_record"
201
+ # "ActiveRecord::Errors".underscore # => active_record/errors
202
+ def underscore(camel_cased_word)
203
+ camel_cased_word.to_s.gsub(/::/, '/').
204
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
205
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
206
+ tr("-", "_").
207
+ downcase
208
+ end
209
+
210
+ # Replaces underscores with dashes in the string.
211
+ #
212
+ # Example:
213
+ # "puni_puni" # => "puni-puni"
214
+ def dasherize(underscored_word)
215
+ underscored_word.gsub(/_/, '-')
216
+ end
217
+
218
+ # Capitalizes the first word and turns underscores into spaces and strips a
219
+ # trailing "_id", if any. Like +titleize+, this is meant for creating pretty output.
220
+ #
221
+ # Examples:
222
+ # "employee_salary" # => "Employee salary"
223
+ # "author_id" # => "Author"
224
+ def humanize(lower_case_and_underscored_word)
225
+ result = lower_case_and_underscored_word.to_s.dup
226
+
227
+ inflections.humans.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
228
+ result.gsub(/_id$/, "").gsub(/_/, " ").capitalize
229
+ end
230
+
231
+ # Removes the module part from the expression in the string.
232
+ #
233
+ # Examples:
234
+ # "ActiveRecord::CoreExtensions::String::Inflections".demodulize # => "Inflections"
235
+ # "Inflections".demodulize # => "Inflections"
236
+ def demodulize(class_name_in_module)
237
+ class_name_in_module.to_s.gsub(/^.*::/, '')
238
+ end
239
+
240
+ # Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
241
+ #
242
+ # ==== Examples
243
+ #
244
+ # class Person
245
+ # def to_param
246
+ # "#{id}-#{name.parameterize}"
247
+ # end
248
+ # end
249
+ #
250
+ # @person = Person.find(1)
251
+ # # => #<Person id: 1, name: "Donald E. Knuth">
252
+ #
253
+ # <%= link_to(@person.name, person_path %>
254
+ # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
255
+ def parameterize(string, sep = '-')
256
+ re_sep = Regexp.escape(sep)
257
+ # replace accented chars with ther ascii equivalents
258
+ parameterized_string = transliterate(string)
259
+ # Turn unwanted chars into the seperator
260
+ parameterized_string.gsub!(/[^a-z0-9\-_\+]+/i, sep)
261
+ # No more than one of the separator in a row.
262
+ parameterized_string.squeeze!(sep)
263
+ # Remove leading/trailing separator.
264
+ parameterized_string.gsub!(/^#{re_sep}|#{re_sep}$/i, '')
265
+ parameterized_string.downcase
266
+ end
267
+
268
+
269
+ # Replaces accented characters with their ascii equivalents.
270
+ def transliterate(string)
271
+ Iconv.iconv('ascii//ignore//translit', 'utf-8', string).to_s
272
+ end
273
+
274
+ # The iconv transliteration code doesn't function correctly
275
+ # on some platforms, but it's very fast where it does function.
276
+ if "foo" != Inflector.transliterate("föö")
277
+ undef_method :transliterate
278
+ def transliterate(string)
279
+ string.mb_chars.normalize(:kd). # Decompose accented characters
280
+ gsub(/[^\x00-\x7F]+/, '') # Remove anything non-ASCII entirely (e.g. diacritics).
281
+ end
282
+ end
283
+
284
+ # Ruby 1.9 introduces an inherit argument for Module#const_get and
285
+ # #const_defined? and changes their default behavior.
286
+ if Module.method(:const_get).arity == 1
287
+ # Tries to find a constant with the name specified in the argument string:
288
+ #
289
+ # "Module".constantize # => Module
290
+ # "Test::Unit".constantize # => Test::Unit
291
+ #
292
+ # The name is assumed to be the one of a top-level constant, no matter whether
293
+ # it starts with "::" or not. No lexical context is taken into account:
294
+ #
295
+ # C = 'outside'
296
+ # module M
297
+ # C = 'inside'
298
+ # C # => 'inside'
299
+ # "C".constantize # => 'outside', same as ::C
300
+ # end
301
+ #
302
+ # NameError is raised when the name is not in CamelCase or the constant is
303
+ # unknown.
304
+ def constantize(camel_cased_word)
305
+ names = camel_cased_word.split('::')
306
+ names.shift if names.empty? || names.first.empty?
307
+
308
+ constant = Object
309
+ names.each do |name|
310
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
311
+ end
312
+ constant
313
+ end
314
+ else
315
+ def constantize(camel_cased_word) #:nodoc:
316
+ names = camel_cased_word.split('::')
317
+ names.shift if names.empty? || names.first.empty?
318
+
319
+ constant = Object
320
+ names.each do |name|
321
+ constant = constant.const_get(name, false) || constant.const_missing(name)
322
+ end
323
+ constant
324
+ end
325
+ end
326
+
327
+ # Turns a number into an ordinal string used to denote the position in an
328
+ # ordered sequence such as 1st, 2nd, 3rd, 4th.
329
+ #
330
+ # Examples:
331
+ # ordinalize(1) # => "1st"
332
+ # ordinalize(2) # => "2nd"
333
+ # ordinalize(1002) # => "1002nd"
334
+ # ordinalize(1003) # => "1003rd"
335
+ def ordinalize(number)
336
+ if (11..13).include?(number.to_i % 100)
337
+ "#{number}th"
338
+ else
339
+ case number.to_i % 10
340
+ when 1; "#{number}st"
341
+ when 2; "#{number}nd"
342
+ when 3; "#{number}rd"
343
+ else "#{number}th"
344
+ end
345
+ end
346
+ end
347
+ end
348
+ end
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
4
+ # All rights reserved.
5
+
6
+ # Permission is granted for use, copying, modification, distribution,
7
+ # and distribution of modified versions of this work as long as the
8
+ # above copyright notice is included.
9
+ #++
10
+
11
+ ######################################################################
12
+ # BlankSlate provides an abstract base class with no predefined
13
+ # methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
14
+ # BlankSlate is useful as a base class when writing classes that
15
+ # depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
16
+ #
17
+ class BlankSlate
18
+ class << self
19
+
20
+ # Hide the method named +name+ in the BlankSlate class. Don't
21
+ # hide +instance_eval+ or any method beginning with "__".
22
+ def hide(name)
23
+ if instance_methods.include?(name.to_s) and
24
+ name !~ /^(__|instance_eval)/
25
+ @hidden_methods ||= {}
26
+ @hidden_methods[name.to_sym] = instance_method(name)
27
+ undef_method name
28
+ end
29
+ end
30
+
31
+ def find_hidden_method(name)
32
+ @hidden_methods ||= {}
33
+ @hidden_methods[name] || superclass.find_hidden_method(name)
34
+ end
35
+
36
+ # Redefine a previously hidden method so that it may be called on a blank
37
+ # slate object.
38
+ def reveal(name)
39
+ bound_method = nil
40
+ unbound_method = find_hidden_method(name)
41
+ fail "Don't know how to reveal method '#{name}'" unless unbound_method
42
+ define_method(name) do |*args|
43
+ bound_method ||= unbound_method.bind(self)
44
+ bound_method.call(*args)
45
+ end
46
+ end
47
+ end
48
+
49
+ instance_methods.each { |m| hide(m) }
50
+ end
51
+
52
+ ######################################################################
53
+ # Since Ruby is very dynamic, methods added to the ancestors of
54
+ # BlankSlate <em>after BlankSlate is defined</em> will show up in the
55
+ # list of available BlankSlate methods. We handle this by defining a
56
+ # hook in the Object and Kernel classes that will hide any method
57
+ # defined after BlankSlate has been loaded.
58
+ #
59
+ module Kernel
60
+ class << self
61
+ alias_method :blank_slate_method_added, :method_added
62
+
63
+ # Detect method additions to Kernel and remove them in the
64
+ # BlankSlate class.
65
+ def method_added(name)
66
+ result = blank_slate_method_added(name)
67
+ return result if self != Kernel
68
+ BlankSlate.hide(name)
69
+ result
70
+ end
71
+ end
72
+ end
73
+
74
+ ######################################################################
75
+ # Same as above, except in Object.
76
+ #
77
+ class Object
78
+ class << self
79
+ alias_method :blank_slate_method_added, :method_added
80
+
81
+ # Detect method additions to Object and remove them in the
82
+ # BlankSlate class.
83
+ def method_added(name)
84
+ result = blank_slate_method_added(name)
85
+ return result if self != Object
86
+ BlankSlate.hide(name)
87
+ result
88
+ end
89
+
90
+ def find_hidden_method(name)
91
+ nil
92
+ end
93
+ end
94
+ end
95
+
96
+ ######################################################################
97
+ # Also, modules included into Object need to be scanned and have their
98
+ # instance methods removed from blank slate. In theory, modules
99
+ # included into Kernel would have to be removed as well, but a
100
+ # "feature" of Ruby prevents late includes into modules from being
101
+ # exposed in the first place.
102
+ #
103
+ class Module
104
+ alias blankslate_original_append_features append_features
105
+ def append_features(mod)
106
+ result = blankslate_original_append_features(mod)
107
+ return result if mod != Object
108
+ instance_methods.each do |name|
109
+ BlankSlate.hide(name)
110
+ end
111
+ result
112
+ end
113
+ end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
4
+ # All rights reserved.
5
+
6
+ # Permission is granted for use, copying, modification, distribution,
7
+ # and distribution of modified versions of this work as long as the
8
+ # above copyright notice is included.
9
+ #++
10
+
11
+ require 'blankslate'
12
+
13
+ ######################################################################
14
+ # BlankSlate has been promoted to a top level name and is now
15
+ # available as a standalone gem. We make the name available in the
16
+ # Builder namespace for compatibility.
17
+ #
18
+ module Builder
19
+ BlankSlate = ::BlankSlate
20
+ end