ant-mapper 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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