ant-mapper 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. data/CHANGE +6 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +25 -0
  4. data/ant.gemspec +48 -0
  5. data/data.tch +0 -0
  6. data/examples/account.rb +71 -0
  7. data/examples/data.tch +0 -0
  8. data/examples/light_cloud.yml +18 -0
  9. data/examples/user.rb +84 -0
  10. data/init.rb +4 -0
  11. data/lib/ant.rb +7 -0
  12. data/lib/ant_mapper.rb +10 -0
  13. data/lib/ant_mapper/adapters/light_cloud.rb +59 -0
  14. data/lib/ant_mapper/adapters/tokyo_cabinet.rb +42 -0
  15. data/lib/ant_mapper/adapters/tokyo_tyrant.rb +14 -0
  16. data/lib/ant_mapper/base.rb +367 -0
  17. data/lib/ant_mapper/callbacks.rb +180 -0
  18. data/lib/ant_mapper/observer.rb +180 -0
  19. data/lib/ant_mapper/validations.rb +687 -0
  20. data/lib/ant_support.rb +4 -0
  21. data/lib/ant_support/callbacks.rb +303 -0
  22. data/lib/ant_support/core_ext.rb +4 -0
  23. data/lib/ant_support/core_ext/array.rb +5 -0
  24. data/lib/ant_support/core_ext/array/extract_options.rb +20 -0
  25. data/lib/ant_support/core_ext/blank.rb +58 -0
  26. data/lib/ant_support/core_ext/class.rb +3 -0
  27. data/lib/ant_support/core_ext/class/attribute_accessors.rb +54 -0
  28. data/lib/ant_support/core_ext/class/inheritable_attributes.rb +140 -0
  29. data/lib/ant_support/core_ext/class/removal.rb +50 -0
  30. data/lib/ant_support/core_ext/duplicable.rb +43 -0
  31. data/lib/ant_support/core_ext/enumerable.rb +72 -0
  32. data/lib/ant_support/core_ext/hash.rb +6 -0
  33. data/lib/ant_support/core_ext/hash/keys.rb +52 -0
  34. data/lib/ant_support/core_ext/module.rb +16 -0
  35. data/lib/ant_support/core_ext/module/aliasing.rb +74 -0
  36. data/lib/ant_support/core_ext/module/attr_accessor_with_default.rb +31 -0
  37. data/lib/ant_support/core_ext/module/attribute_accessors.rb +58 -0
  38. data/lib/ant_support/core_ext/object.rb +1 -0
  39. data/lib/ant_support/core_ext/object/extending.rb +80 -0
  40. data/lib/ant_support/core_ext/string.rb +7 -0
  41. data/lib/ant_support/core_ext/string/inflections.rb +51 -0
  42. data/spec/case/callbacks_observers_test.rb +38 -0
  43. data/spec/case/callbacks_test.rb +417 -0
  44. data/spec/case/create_object_test.rb +56 -0
  45. data/spec/case/set_class_name_test.rb +17 -0
  46. data/spec/case/validations_test.rb +1482 -0
  47. data/spec/helper.rb +15 -0
  48. data/spec/light_cloud.yml +18 -0
  49. data/spec/model/account.rb +3 -0
  50. data/spec/model/topic.rb +28 -0
  51. data/spec/model/user.rb +4 -0
  52. metadata +125 -0
@@ -0,0 +1,4 @@
1
+ Dir[File.dirname(__FILE__) + "/ant_support/*.rb"].sort.each do |path|
2
+ filename = File.basename(path)
3
+ require "ant_support/#{filename}"
4
+ end
@@ -0,0 +1,303 @@
1
+ module AntSupport
2
+ # Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
3
+ # before or after an alteration of the object state.
4
+ #
5
+ # Mixing in this module allows you to define callbacks in your class.
6
+ #
7
+ # Example:
8
+ # class Storage
9
+ # include AntSupport::Callbacks
10
+ #
11
+ # define_callbacks :before_save, :after_save
12
+ # end
13
+ #
14
+ # class ConfigStorage < Storage
15
+ # before_save :saving_message
16
+ # def saving_message
17
+ # puts "saving..."
18
+ # end
19
+ #
20
+ # after_save do |object|
21
+ # puts "saved"
22
+ # end
23
+ #
24
+ # def save
25
+ # run_callbacks(:before_save)
26
+ # puts "- save"
27
+ # run_callbacks(:after_save)
28
+ # end
29
+ # end
30
+ #
31
+ # config = ConfigStorage.new
32
+ # config.save
33
+ #
34
+ # Output:
35
+ # saving...
36
+ # - save
37
+ # saved
38
+ #
39
+ # Callbacks from parent classes are inherited.
40
+ #
41
+ # Example:
42
+ # class Storage
43
+ # include AntSupport::Callbacks
44
+ #
45
+ # define_callbacks :before_save, :after_save
46
+ #
47
+ # before_save :prepare
48
+ # def prepare
49
+ # puts "preparing save"
50
+ # end
51
+ # end
52
+ #
53
+ # class ConfigStorage < Storage
54
+ # before_save :saving_message
55
+ # def saving_message
56
+ # puts "saving..."
57
+ # end
58
+ #
59
+ # after_save do |object|
60
+ # puts "saved"
61
+ # end
62
+ #
63
+ # def save
64
+ # run_callbacks(:before_save)
65
+ # puts "- save"
66
+ # run_callbacks(:after_save)
67
+ # end
68
+ # end
69
+ #
70
+ # config = ConfigStorage.new
71
+ # config.save
72
+ #
73
+ # Output:
74
+ # preparing save
75
+ # saving...
76
+ # - save
77
+ # saved
78
+ module Callbacks
79
+ class CallbackChain < Array
80
+ def self.build(kind, *methods, &block)
81
+ methods, options = extract_options(*methods, &block)
82
+ methods.map! { |method| Callback.new(kind, method, options) }
83
+ new(methods)
84
+ end
85
+
86
+ def run(object, options = {}, &terminator)
87
+ enumerator = options[:enumerator] || :each
88
+
89
+ unless block_given?
90
+ send(enumerator) { |callback| callback.call(object) }
91
+ else
92
+ send(enumerator) do |callback|
93
+ result = callback.call(object)
94
+ break result if terminator.call(result, object)
95
+ end
96
+ end
97
+ end
98
+
99
+ # TODO: Decompose into more Array like behavior
100
+ def replace_or_append!(chain)
101
+ if index = index(chain)
102
+ self[index] = chain
103
+ else
104
+ self << chain
105
+ end
106
+ self
107
+ end
108
+
109
+ def find(callback, &block)
110
+ select { |c| c == callback && (!block_given? || yield(c)) }.first
111
+ end
112
+
113
+ def delete(callback)
114
+ super(callback.is_a?(Callback) ? callback : find(callback))
115
+ end
116
+
117
+ private
118
+ def self.extract_options(*methods, &block)
119
+ methods.flatten!
120
+ options = methods.extract_options!
121
+ methods << block if block_given?
122
+ return methods, options
123
+ end
124
+
125
+ def extract_options(*methods, &block)
126
+ self.class.extract_options(*methods, &block)
127
+ end
128
+ end
129
+
130
+ class Callback
131
+ attr_reader :kind, :method, :identifier, :options
132
+
133
+ def initialize(kind, method, options = {})
134
+ @kind = kind
135
+ @method = method
136
+ @identifier = options[:identifier]
137
+ @options = options
138
+ end
139
+
140
+ def ==(other)
141
+ case other
142
+ when Callback
143
+ (self.identifier && self.identifier == other.identifier) || self.method == other.method
144
+ else
145
+ (self.identifier && self.identifier == other) || self.method == other
146
+ end
147
+ end
148
+
149
+ def eql?(other)
150
+ self == other
151
+ end
152
+
153
+ def dup
154
+ self.class.new(@kind, @method, @options.dup)
155
+ end
156
+
157
+ def hash
158
+ if @identifier
159
+ @identifier.hash
160
+ else
161
+ @method.hash
162
+ end
163
+ end
164
+
165
+ def call(*args, &block)
166
+ evaluate_method(method, *args, &block) if should_run_callback?(*args)
167
+ rescue LocalJumpError
168
+ raise ArgumentError,
169
+ "Cannot yield from a Proc type filter. The Proc must take two " +
170
+ "arguments and execute #call on the second argument."
171
+ end
172
+
173
+ private
174
+ def evaluate_method(method, *args, &block)
175
+ case method
176
+ when Symbol
177
+ object = args.shift
178
+ object.send(method, *args, &block)
179
+ when String
180
+ eval(method, args.first.instance_eval { binding })
181
+ when Proc, Method
182
+ method.call(*args, &block)
183
+ else
184
+ if method.respond_to?(kind)
185
+ method.send(kind, *args, &block)
186
+ else
187
+ raise ArgumentError,
188
+ "Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
189
+ "a block to be invoked, or an object responding to the callback method."
190
+ end
191
+ end
192
+ end
193
+
194
+ def should_run_callback?(*args)
195
+ if options[:if]
196
+ evaluate_method(options[:if], *args)
197
+ elsif options[:unless]
198
+ !evaluate_method(options[:unless], *args)
199
+ else
200
+ true
201
+ end
202
+ end
203
+ end
204
+
205
+ def self.included(base)
206
+ base.extend ClassMethods
207
+ end
208
+
209
+ module ClassMethods
210
+ # 定义回调
211
+ #
212
+ # 例如:
213
+ # callbacks = %w(before_save)
214
+ # base.define_callbacks *callbacks
215
+ # 等价于
216
+ # class << base
217
+ # def before_save(*methods,&block)
218
+ # callbacks= CallbackChain.build(:before_save,*methods,&block)
219
+ # (@before_save_callbacks ||= CallbackChain.new).concat callbacks
220
+ # end
221
+ #
222
+ # def before_save_callback_chain
223
+ # @before_save_callbacks ||= CallbackChain.new
224
+ # if superclass.respond_to?(:before_save_callback_chain)
225
+ # CallbackChain.new(superclass.before_save_callback_chain+@before_save_callbacks)
226
+ # else
227
+ # @before_save_callbacks
228
+ # end
229
+ # end
230
+ # end
231
+ def define_callbacks(*callbacks)
232
+ callbacks.each do |callback|
233
+ class_eval <<-"end_eval"
234
+ def self.#{callback}(*methods, &block)
235
+ callbacks = CallbackChain.build(:#{callback}, *methods, &block)
236
+ (@#{callback}_callbacks ||= CallbackChain.new).concat callbacks
237
+ end
238
+
239
+ def self.#{callback}_callback_chain
240
+ @#{callback}_callbacks ||= CallbackChain.new
241
+
242
+ if superclass.respond_to?(:#{callback}_callback_chain)
243
+ CallbackChain.new(superclass.#{callback}_callback_chain + @#{callback}_callbacks)
244
+ else
245
+ @#{callback}_callbacks
246
+ end
247
+ end
248
+ end_eval
249
+ end
250
+ end
251
+ end
252
+
253
+ # Runs all the callbacks defined for the given options.
254
+ #
255
+ # If a block is given it will be called after each callback receiving as arguments:
256
+ #
257
+ # * the result from the callback
258
+ # * the object which has the callback
259
+ #
260
+ # If the result from the block evaluates to false, the callback chain is stopped.
261
+ #
262
+ # Example:
263
+ # class Storage
264
+ # include AntSupport::Callbacks
265
+ #
266
+ # define_callbacks :before_save, :after_save
267
+ # end
268
+ #
269
+ # class ConfigStorage < Storage
270
+ # before_save :pass
271
+ # before_save :pass
272
+ # before_save :stop
273
+ # before_save :pass
274
+ #
275
+ # def pass
276
+ # puts "pass"
277
+ # end
278
+ #
279
+ # def stop
280
+ # puts "stop"
281
+ # return false
282
+ # end
283
+ #
284
+ # def save
285
+ # result = run_callbacks(:before_save) { |result, object| result == false }
286
+ # puts "- save" if result
287
+ # end
288
+ # end
289
+ #
290
+ # config = ConfigStorage.new
291
+ # config.save
292
+ #
293
+ # Output:
294
+ # pass
295
+ # pass
296
+ # stop
297
+ def run_callbacks(kind, options = {}, &block)
298
+ # self.class.send("#{kind}_callback_chain")
299
+ #
300
+ self.class.send("#{kind}_callback_chain").run(self, options, &block)
301
+ end
302
+ end
303
+ end
@@ -0,0 +1,4 @@
1
+ Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].sort.each do |path|
2
+ filename = File.basename(path)
3
+ require "ant_support/core_ext/#{filename}"
4
+ end
@@ -0,0 +1,5 @@
1
+ require 'ant_support/core_ext/array/extract_options'
2
+
3
+ class Array #:nodoc:
4
+ include AntSupport::CoreExtensions::Array::ExtractOptions
5
+ end
@@ -0,0 +1,20 @@
1
+ module AntSupport #:nodoc:
2
+ module CoreExtensions #:nodoc:
3
+ module Array #:nodoc:
4
+ module ExtractOptions
5
+ # Extracts options from a set of arguments. Removes and returns the last
6
+ # element in the array if it's a hash, otherwise returns a blank hash.
7
+ #
8
+ # def options(*args)
9
+ # args.extract_options!
10
+ # end
11
+ #
12
+ # options(1, 2) # => {}
13
+ # options(1, 2, :a => :b) # => {:a=>:b}
14
+ def extract_options!
15
+ last.is_a?(::Hash) ? pop : {}
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,58 @@
1
+ class Object
2
+ # An object is blank if it's false, empty, or a whitespace string.
3
+ # For example, "", " ", +nil+, [], and {} are blank.
4
+ #
5
+ # This simplifies
6
+ #
7
+ # if !address.nil? && !address.empty?
8
+ #
9
+ # to
10
+ #
11
+ # if !address.blank?
12
+ def blank?
13
+ respond_to?(:empty?) ? empty? : !self
14
+ end
15
+
16
+ # An object is present if it's not blank.
17
+ def present?
18
+ !blank?
19
+ end
20
+ end
21
+
22
+ class NilClass #:nodoc:
23
+ def blank?
24
+ true
25
+ end
26
+ end
27
+
28
+ class FalseClass #:nodoc:
29
+ def blank?
30
+ true
31
+ end
32
+ end
33
+
34
+ class TrueClass #:nodoc:
35
+ def blank?
36
+ false
37
+ end
38
+ end
39
+
40
+ class Array #:nodoc:
41
+ alias_method :blank?, :empty?
42
+ end
43
+
44
+ class Hash #:nodoc:
45
+ alias_method :blank?, :empty?
46
+ end
47
+
48
+ class String #:nodoc:
49
+ def blank?
50
+ self !~ /\S/
51
+ end
52
+ end
53
+
54
+ class Numeric #:nodoc:
55
+ def blank?
56
+ false
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ require 'ant_support/core_ext/class/attribute_accessors'
2
+ require 'ant_support/core_ext/class/inheritable_attributes'
3
+ require 'ant_support/core_ext/class/removal'
@@ -0,0 +1,54 @@
1
+ # Extends the class object with class and instance accessors for class attributes,
2
+ # just like the native attr* accessors for instance attributes.
3
+ #
4
+ # class Person
5
+ # cattr_accessor :hair_colors
6
+ # end
7
+ #
8
+ # Person.hair_colors = [:brown, :black, :blonde, :red]
9
+ class Class
10
+ def cattr_reader(*syms)
11
+ syms.flatten.each do |sym|
12
+ next if sym.is_a?(Hash)
13
+ class_eval(<<-EOS, __FILE__, __LINE__)
14
+ unless defined? @@#{sym}
15
+ @@#{sym} = nil
16
+ end
17
+
18
+ def self.#{sym}
19
+ @@#{sym}
20
+ end
21
+
22
+ def #{sym}
23
+ @@#{sym}
24
+ end
25
+ EOS
26
+ end
27
+ end
28
+
29
+ def cattr_writer(*syms)
30
+ options = syms.extract_options!
31
+ syms.flatten.each do |sym|
32
+ class_eval(<<-EOS, __FILE__, __LINE__)
33
+ unless defined? @@#{sym}
34
+ @@#{sym} = nil
35
+ end
36
+
37
+ def self.#{sym}=(obj)
38
+ @@#{sym} = obj
39
+ end
40
+
41
+ #{"
42
+ def #{sym}=(obj)
43
+ @@#{sym} = obj
44
+ end
45
+ " unless options[:instance_writer] == false }
46
+ EOS
47
+ end
48
+ end
49
+
50
+ def cattr_accessor(*syms)
51
+ cattr_reader(*syms)
52
+ cattr_writer(*syms)
53
+ end
54
+ end