Neurogami-jimpanzee 1.0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,379 @@
1
+ require 'monkeybars/validated_hash'
2
+
3
+ module Monkeybars
4
+ # This is an internal class used only by Monkeybars::View
5
+ #
6
+ # A Mapping records the relationship between the fields of a model or
7
+ # transfer hash and the fields of a view. Mappings are created for each call
8
+ # to View.map. During first usage, the mappings are inspected for validity
9
+ # and are assigned a type (one of the constants defined in Mapping) to speed
10
+ # up processing. Invalid mappings raise an exception.
11
+ class Mapping #:nodoc:
12
+ DIRECTION_TO_VIEW = :to_view
13
+ DIRECTION_FROM_VIEW = :from_view
14
+ DIRECTION_BOTH = :both
15
+ MODEL = :model
16
+ TRANSFER = :transfer
17
+
18
+ class << self
19
+ alias_method :__new__, :new
20
+ end
21
+
22
+ def self.new(mapping_options = {})
23
+ mapping_options.validate_only(:view, :model, :transfer, :using, :ignoring, :translate_using)
24
+ mapping_options.extend HashMappingValidation
25
+
26
+ if mapping_options.properties_only?
27
+ PropertyMapping.__new__(mapping_options)
28
+ elsif mapping_options.methods_only?
29
+ RawMapping.__new__(mapping_options)
30
+ elsif mapping_options.both_properties_and_methods?
31
+ MethodMapping.__new__(mapping_options)
32
+ else
33
+ raise InvalidMappingError, "Cannot determine mapping type with parameters #{mapping_options.inspect}"
34
+ end
35
+ end
36
+
37
+ def initialize(mapping_options = {})
38
+ @view_property = mapping_options[:view] || nil
39
+ @model_property = mapping_options[:model] || nil
40
+ @transfer_property = mapping_options[:transfer] || nil
41
+ @data_translation_hash = mapping_options[:translate_using]
42
+
43
+ @to_view_method, @from_view_method = if mapping_options[:using]
44
+ if mapping_options[:using].kind_of? Array
45
+ [mapping_options[:using][0], mapping_options[:using][1]]
46
+ else
47
+ [mapping_options[:using], nil]
48
+ end
49
+ else
50
+ [nil, nil]
51
+ end
52
+
53
+ @event_types_to_ignore = if mapping_options[:ignoring]
54
+ if mapping_options[:ignoring].kind_of? Array
55
+ mapping_options[:ignoring]
56
+ else
57
+ [mapping_options[:ignoring]]
58
+ end
59
+ else
60
+ []
61
+ end
62
+
63
+ if mapping_options.both_model_and_transfer_present?
64
+ raise InvalidMappingError, "Both model and transfer parameters were given"
65
+ elsif mapping_options.at_least_one_property_present? and !mapping_options.both_properties_present?
66
+ raise InvalidMappingError, "Both a view and a model/transfer property must be provided"
67
+ end
68
+ set_direction(mapping_options)
69
+ end
70
+
71
+ def maps_to_view?
72
+ (DIRECTION_BOTH == @direction) or (DIRECTION_TO_VIEW == @direction)
73
+ end
74
+
75
+ def maps_from_view?
76
+ (DIRECTION_BOTH == @direction) or (DIRECTION_FROM_VIEW == @direction)
77
+ end
78
+
79
+ def to_view(view, model, transfer)
80
+ disable_declared_handlers(view) do
81
+ if model_mapping?
82
+ model_to_view(view, model)
83
+ else
84
+ transfer_to_view(view, transfer) if mapped_transfer_key_present?(transfer)
85
+ end
86
+ end
87
+ end
88
+
89
+ def from_view(view, model, transfer)
90
+ disable_declared_handlers(view) do
91
+ if model_mapping?
92
+ model_from_view(view, model)
93
+ elsif transfer_mapping?
94
+ transfer_from_view(view, transfer)
95
+ end
96
+ end
97
+ end
98
+
99
+ def model_mapping?
100
+ !@model_property.nil?
101
+ end
102
+
103
+ def transfer_mapping?
104
+ !@transfer_property.nil?
105
+ end
106
+
107
+ private
108
+
109
+ def mapped_transfer_key_present?(transfer)
110
+ transfer.has_key? @transfer_property
111
+ end
112
+
113
+ def set_direction(mapping_options)
114
+ @direction = if mapping_options.both_methods_present?
115
+ DIRECTION_BOTH
116
+ elsif mapping_options.to_view_method_present?
117
+ DIRECTION_TO_VIEW
118
+ else
119
+ DIRECTION_FROM_VIEW
120
+ end
121
+ end
122
+
123
+ def disable_declared_handlers(view, &block)
124
+ if @event_types_to_ignore.empty?
125
+ yield
126
+ else
127
+ field = view.get_field_value(/^(\w+)\.?/.match(@view_property)[1])
128
+ @event_types_to_ignore.each do |event_type|
129
+ unless event_type.to_s == "document"
130
+ field.disable_handlers(event_type, &block)
131
+ else
132
+ field.document.disable_handlers(event_type, &block)
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ class BasicPropertyMapping < Mapping
140
+ def to_s
141
+ model_or_transfer_key = model_mapping? ? ':model' : ':transfer'
142
+ model_or_transfer_property = model_mapping? ? @model_property : @transfer_property
143
+ ":view => #{@view_property.inspect}, #{model_or_transfer_key} => #{model_or_transfer_property.inspect}"
144
+ end
145
+
146
+ def model_to_view(view, model)
147
+ begin
148
+ instance_eval("view.#{@view_property} = model.#{@model_property}", __FILE__, __LINE__)
149
+ rescue NoMethodError
150
+ raise InvalidMappingError, "Either model.#{@model_property} or self.#{@view_property} in #{view.class} is not valid."
151
+ rescue TypeError => e
152
+ raise InvalidMappingError, "Invalid types when assigning from model.#{@model_property} to self.#{@view_property}, #{e.message} in #{view.class}"
153
+ rescue Monkeybars::UndefinedComponentError
154
+ raise InvalidMappingError, "The view property #{@view_property} was not found on view #{view.class}"
155
+ rescue SyntaxError, Exception => e
156
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
157
+ end
158
+ end
159
+
160
+ def transfer_to_view(view, transfer)
161
+ begin
162
+ instance_eval("view.#{@view_property} = transfer[#{@transfer_property.inspect}]", __FILE__, __LINE__)
163
+ rescue NoMethodError
164
+ raise InvalidMappingError, "Either transfer[#{@transfer_property.inspect}] or self.#{@view_property} in #{view.class} is not valid."
165
+ rescue TypeError => e
166
+ raise InvalidMappingError, "Invalid types when assigning from transfer[#{@transfer_property.inspect}] to self.#{@view_property}, #{e.class}: #{e.message} in #{view.class}"
167
+ rescue SyntaxError, Exception => e
168
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
169
+ end
170
+ end
171
+
172
+ def model_from_view(view, model)
173
+ begin
174
+ instance_eval("model.#{@model_property} = view.#{@view_property}", __FILE__, __LINE__)
175
+ rescue NoMethodError
176
+ raise InvalidMappingError, "Either model.#{@model_property} or self.#{@view_property} in #{view.class} is not valid."
177
+ rescue TypeError => e
178
+ raise InvalidMappingError, "Invalid types when assigning from model.#{@model_property} to self.#{@view_property}, #{e.message} in #{view.class}"
179
+ rescue SyntaxError, Exception => e
180
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
181
+ end
182
+ end
183
+
184
+ def transfer_from_view(view, transfer)
185
+ begin
186
+ instance_eval("transfer[#{@transfer_property.inspect}] = view.#{@view_property}", __FILE__, __LINE__)
187
+ rescue NoMethodError
188
+ raise InvalidMappingError, "Either transfer[#{@transfer_property.inspect}] or self.#{@view_property} in #{view.class} is not valid."
189
+ rescue TypeError => e
190
+ raise InvalidMappingError, "Invalid types when assigning from transfer[#{@transfer_property.inspect}] to self.#{@view_property}, #{e.message} in #{view.class}"
191
+ rescue SyntaxError, Exception => e
192
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
193
+ end
194
+ end
195
+
196
+ private
197
+ def self.new(*args)
198
+ raise "#{self} is not a concrete class"
199
+ end
200
+ end
201
+
202
+ class RawMapping < Mapping
203
+ def to_view(view, model, transfer)
204
+ disable_declared_handlers(view) do
205
+ view.method(@to_view_method).call(model, transfer)
206
+ end
207
+ end
208
+
209
+ def from_view(view, model, transfer)
210
+ view.method(@from_view_method).call(model, transfer) unless @from_view_method.nil?
211
+ end
212
+ end
213
+
214
+ class PropertyMapping < BasicPropertyMapping
215
+ def set_direction(mapping_options)
216
+ @direction = DIRECTION_BOTH
217
+ end
218
+ end
219
+
220
+ class MethodMapping < BasicPropertyMapping
221
+
222
+ def initialize(mapping_properties)
223
+ super
224
+ if using_translation?
225
+ @to_view_translation = @data_translation_hash
226
+ @from_view_translation = @data_translation_hash.invert
227
+ end
228
+ end
229
+
230
+ def to_s
231
+ using_key = using_translation? ? ':using_translation' : ':using'
232
+ using_value = using_translation? ? @data_translation_hash.inspect : "[#{@to_view_method.inspect}, #{@from_view_method.inspect}]"
233
+ super << " #{using_key} => #{using_value}"
234
+ end
235
+
236
+ def using_translation?
237
+ !@data_translation_hash.nil?
238
+ end
239
+
240
+ def model_to_view(view, model)
241
+ if using_translation?
242
+ model_data = instance_eval("model.#{@model_property}", __FILE__, __LINE__)
243
+ unless @to_view_translation.has_key? model_data
244
+ raise TranslationError, "The key #{model_data.inspect} for model #{model.class} does not exist #{@to_view_translation.inspect}"
245
+ end
246
+
247
+ instance_eval("view.#{@view_property} = @to_view_translation[model_data]", __FILE__, __LINE__)
248
+ elsif :default == @to_view_method
249
+ super
250
+ else
251
+ instance_eval("view.#{@view_property} = view.method(@to_view_method).call(model.#{@model_property})", __FILE__, __LINE__)
252
+ end
253
+ rescue NameError => e
254
+ raise InvalidMappingError, "Either view.#{@view_property} or view.#{@to_view_method}(#{@model_property}) is not valid.\nOriginal error: #{e}\n#{e.message}"
255
+ rescue SyntaxError, Exception => e
256
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
257
+ end
258
+
259
+ def transfer_to_view(view, transfer)
260
+ if using_translation?
261
+ transfer_data = instance_eval("transfer[#{@transfer_property.inspect}]", __FILE__, __LINE__)
262
+ unless @to_view_translation.has_key? transfer_data
263
+ raise TranslationError, "The key #{transfer_data.inspect} for transfer does not exist #{@to_view_translation.inspect}"
264
+ end
265
+ instance_eval("view.#{@view_property} = @to_view_translation[transfer_data]", __FILE__, __LINE__)
266
+ elsif :default == @to_view_method
267
+ super
268
+ else
269
+ instance_eval("view.#{@view_property} = view.method(@to_view_method).call(transfer[#{@transfer_property.inspect}])", __FILE__, __LINE__)
270
+ end
271
+ rescue NameError => e
272
+ raise InvalidMappingError, "Either view.#{@view_property} or view.#{@to_view_method}(#{@transfer_property}) is not valid.\nOriginal error: #{e}\n#{e.message}"
273
+ rescue SyntaxError, Exception => e
274
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
275
+ end
276
+
277
+ def model_from_view(view, model)
278
+ if using_translation?
279
+ view_data = instance_eval("view.#{@view_property}", __FILE__, __LINE__)
280
+ unless @from_view_translation.has_key? view_data
281
+ raise TranslationError, "The key #{view_data.inspect} for view #{view.class} does not exist #{@from_view_translation.inspect}"
282
+ end
283
+ instance_eval("model.#{@model_property} = @from_view_translation[view_data]", __FILE__, __LINE__)
284
+ elsif :default == @from_view_method
285
+ super
286
+ else
287
+ instance_eval("model.#{@model_property} = view.method(@from_view_method).call(view.#{@view_property})", __FILE__, __LINE__)
288
+ end
289
+ rescue NameError => e
290
+ raise InvalidMappingError, "Either model.#{@model_property} or view.#{@from_view_method}(#{@view_property}) is not valid.\nOriginal error: #{e}\n#{e.message}"
291
+ rescue SyntaxError, Exception => e
292
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}", e.backtrace
293
+ end
294
+
295
+ def transfer_from_view(view, transfer)
296
+ if using_translation?
297
+ view_data = instance_eval("view.#{@view_property}", __FILE__, __LINE__)
298
+ unless @from_view_translation.has_key? view_data
299
+ raise TranslationError, "The key #{view_data.inspect} for view #{view.class} does not exist #{@from_view_translation.inspect}"
300
+ end
301
+ instance_eval("transfer[#{@transfer_property.inspect}] = @from_view_translation[view_data]", __FILE__, __LINE__)
302
+ elsif :default == @from_view_method
303
+ super
304
+ else
305
+ instance_eval("transfer[#{@transfer_property.inspect}] = view.method(@from_view_method).call(view.#{@view_property})", __FILE__, __LINE__)
306
+ end
307
+ rescue NameError => e
308
+ raise InvalidMappingError, "Either transfer[#{@transfer_property}] or view.#{@from_view_method}(#{@view_property}) is not valid.\nOriginal error: #{e}\n#{e.message}"
309
+ rescue SyntaxError, Exception => e
310
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
311
+ end
312
+ end
313
+
314
+
315
+ module HashMappingValidation
316
+ def properties_only?
317
+ properties = (at_least_one_property_present? and !at_least_one_method_present?)
318
+ (properties and not translate_using_present?) ? true : false
319
+ end
320
+
321
+ def both_properties_and_methods?
322
+ using = (both_properties_present? and at_least_one_method_present?)
323
+ translation = translate_using_present?
324
+ ((using or translation) and not (using and translation)) ? true : false
325
+ end
326
+
327
+ def methods_only?
328
+ (!at_least_one_property_present? and at_least_one_method_present?) ? true : false
329
+ end
330
+
331
+ def translate_using_present?
332
+ !self[:translate_using].nil?
333
+ end
334
+
335
+ def both_properties_present?
336
+ !self[:view].nil? and (!self[:model].nil? or !self[:transfer].nil?)
337
+ end
338
+
339
+ def both_model_and_transfer_present?
340
+ !self[:model].nil? and !self[:transfer].nil?
341
+ end
342
+
343
+ def both_methods_present?
344
+ ((!to_view_method.nil? and !from_view_method.nil?) or translate_using_present?)
345
+ end
346
+
347
+ def to_view_method_present?
348
+ !to_view_method.nil?
349
+ end
350
+
351
+ def from_view_method_present?
352
+ !from_view_method.nil?
353
+ end
354
+
355
+ def at_least_one_property_present?
356
+ !self[:view].nil? or !self[:model].nil? or !self[:transfer].nil?
357
+ end
358
+
359
+ def at_least_one_method_present?
360
+ !to_view_method.nil? or !from_view_method.nil?
361
+ end
362
+
363
+ def to_view_method
364
+ if self[:using].kind_of? Array
365
+ self[:using].first
366
+ else
367
+ self[:using]
368
+ end
369
+ end
370
+
371
+ def from_view_method
372
+ if self[:using].kind_of? Array
373
+ self[:using][1]
374
+ else
375
+ nil
376
+ end
377
+ end
378
+ end
379
+ end
@@ -0,0 +1,114 @@
1
+ module Monkeybars
2
+ class Nesting
3
+ class << self
4
+ alias_method :__new__, :new
5
+ end
6
+
7
+ def self.new(nesting_options = {})
8
+ nesting_options.validate_only(:sub_view, :using, :view)
9
+ nesting_options.extend Monkeybars::HashNestingValidation
10
+
11
+ if nesting_options.property_only?
12
+ PropertyNesting.__new__(nesting_options)
13
+ elsif nesting_options.methods_only?
14
+ MethodNesting.__new__(nesting_options)
15
+ else
16
+ raise InvalidNestingError, "Cannot determine nesting type with parameters #{nesting_options.inspect}"
17
+ end
18
+ end
19
+
20
+ def initialize(properties)
21
+ @sub_view = properties[:sub_view]
22
+ end
23
+ end
24
+
25
+ class PropertyNesting < Nesting
26
+ def initialize(properties)
27
+ super
28
+ @view_property = properties[:view]
29
+ end
30
+
31
+ def nests_with_add?
32
+ true
33
+ end
34
+
35
+ def nests_with_remove?
36
+ true
37
+ end
38
+
39
+ def add(view, nested_view, nested_component, model, transfer)
40
+ instance_eval("view.#{@view_property}.add nested_component")
41
+ end
42
+
43
+ def remove(view, nested_view, nested_component, model, transfer)
44
+ instance_eval("view.#{@view_property}.remove nested_component")
45
+ end
46
+ end
47
+
48
+ class MethodNesting < Nesting
49
+ def initialize(nesting_options)
50
+ super
51
+ @add_method, @remove_method = if nesting_options[:using].kind_of? Array
52
+ [nesting_options[:using][0], nesting_options[:using][1]]
53
+ else
54
+ [nesting_options[:using], nil]
55
+ end
56
+ end
57
+
58
+ def nests_with_add?
59
+ !@add_method.nil?
60
+ end
61
+
62
+ def nests_with_remove?
63
+ !@remove_method.nil?
64
+ end
65
+
66
+ def add(view, nested_view, nested_component, model, transfer)
67
+ #instance_eval("view.#{@add_method}(@sub_view, model, transfer)")
68
+ view.send(@add_method, nested_view, nested_component, model, transfer)
69
+ end
70
+
71
+ def remove(view, nested_view, nested_component, model, transfer)
72
+ #instance_eval("view.#{@remove_method}(@sub_view, model, transfer)")
73
+ view.send(@remove_method, nested_view, nested_component, model, transfer)
74
+ end
75
+ end
76
+
77
+ module HashNestingValidation
78
+ def property_only?
79
+ property_present? and not (to_view_method_present? and from_view_method_present?)
80
+ end
81
+
82
+ def methods_only?
83
+ (to_view_method_present? and from_view_method_present?) and not property_present?
84
+ end
85
+
86
+ def property_present?
87
+ !self[:view].nil?
88
+ end
89
+
90
+ def to_view_method_present?
91
+ !to_view_method.nil?
92
+ end
93
+
94
+ def from_view_method_present?
95
+ !from_view_method.nil?
96
+ end
97
+
98
+ def to_view_method
99
+ if self[:using].kind_of? Array
100
+ self[:using].first
101
+ else
102
+ self[:using]
103
+ end
104
+ end
105
+
106
+ def from_view_method
107
+ if self[:using].kind_of? Array
108
+ self[:using][1]
109
+ else
110
+ nil
111
+ end
112
+ end
113
+ end
114
+ end