formize 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,598 @@
1
+ module Formize
2
+
3
+ # Permits to not quote text in inspect method
4
+ class Code < String
5
+
6
+ def inspect
7
+ self.to_s
8
+ end
9
+
10
+ end
11
+
12
+
13
+ class Generator
14
+
15
+ attr_accessor :form, :elements, :record_name, :partial, :controller
16
+
17
+ def initialize(form, controller)
18
+ @form = form
19
+ @controller = controller
20
+ @record_name = @form.record_name
21
+ @elements = form.all_elements
22
+ @partials = @elements.select{|e| !e.depend_on.nil? or e.options[:new]}
23
+ end
24
+
25
+
26
+ # Generates the controller method from a form object
27
+ def controller_code
28
+ code = "def #{form.controller_method_name}\n"
29
+
30
+ # Mono_choice search/filter
31
+ items = form.mono_choices
32
+ if items.size > 0
33
+ code << " if params[:unroll]\n"
34
+ events = form.mono_choices.collect do |mono_choice|
35
+ event = "if params[:unroll] == '#{mono_choice.html_id}'\n"
36
+
37
+ for depended in mono_choice.dependeds
38
+ df = form.fields[depended[:name]]
39
+ event << " #{df.name} = " << (df.reflection.nil? ? "params[:#{df.input_id}]" : "#{df.reflection.class_name}.find_by_id(params[:#{df.input_id}])") << "\n"
40
+ # locals[df.name.to_sym] = Code.new(df.name)
41
+ end
42
+
43
+ event << mono_choice_search_code(mono_choice).strip.gsub(/^/, ' ') << "\n"
44
+ event << "end\n"
45
+ end
46
+ code << events.collect{|e| e.gsub(/^/, ' ')}.join
47
+ code << " end\n"
48
+ end
49
+
50
+ # Dependencies refresh
51
+ items = @partials
52
+ if items.size > 0
53
+ code << " if params[:refresh]\n"
54
+ code << " #{record_name} = #{form.model.name}.find(params[:id]) if params[:id].to_i > 0\n"
55
+ code << " #{record_name} ||= #{form.model.name}.new\n"
56
+ code << " @#{record_name} = #{record_name}\n"
57
+ events = items.collect do |dependent|
58
+ event = "if params[:refresh] == '#{dependent.html_id}'\n"
59
+ locals = {record_name.to_sym => Code.new(record_name)}
60
+ for depended in dependent.dependeds
61
+ df = form.fields[depended[:name]]
62
+ event << " #{record_name}.#{df.name} = " << (df.reflection.nil? ? "params[:#{df.input_id}]" : "#{df.reflection.class_name}.find_by_id(params[:#{df.input_id}])") << "\n"
63
+ # locals[df.name.to_sym] = Code.new(df.name)
64
+ end
65
+ event << " render(:inline=>'<%=#{dependent.prototype}-%>', :locals=>#{locals.inspect})\n"
66
+ event << "end\n"
67
+ end
68
+ code << events.collect{|e| e.gsub(/^/, ' ')}.join
69
+ code << " end\n"
70
+ end
71
+
72
+ # End
73
+ code << "end\n"
74
+ code.gsub!(/end\s*if/, 'elsif')
75
+ # raise code
76
+ list = code.split("\n"); list.each_index{|x| puts((x+1).to_s.rjust(4)+": "+list[x])}
77
+ return code
78
+ end
79
+
80
+
81
+
82
+ # Generates the view method from a form object
83
+ def view_code
84
+ code = ""
85
+
86
+ varh = 'html'
87
+
88
+ # Build view methods assimilated to partials
89
+ for element in @partials
90
+ code << "# #{element.class.name}: #{element.html_id}/#{element.name}\n"
91
+ code << view_method_code(element, varh)
92
+ end
93
+
94
+
95
+ code << "\n"
96
+ code << "def #{form.options[:view_fields_method_name]}(#{form.record_name}=nil)\n"
97
+ code << " #{form.record_name} = @#{form.record_name} unless #{form.record_name}.is_a?(#{form.model.name})\n"
98
+ code << " #{varh} = ''\n"
99
+ for element in form.elements
100
+ code << view_method_call(element, varh).strip.gsub(/^/, ' ') << "\n" #
101
+ # code << " #{varh} << " << element.method_call_code.gsub(/^/, ' ').strip << "\n"
102
+ end
103
+ code << " return #{varh}\n"
104
+ code << "end\n"
105
+
106
+ code << "\n"
107
+ code << "def #{form.options[:view_form_method_name]}(#{form.record_name}=nil)\n"
108
+ code << " #{form.record_name} = @#{form.record_name} unless #{form.record_name}.is_a?(#{form.model.name})\n"
109
+ code << " return form_for(#{form.record_name}) do\n"
110
+ code << " #{form.options[:view_fields_method_name]}(#{form.record_name})\n"
111
+ code << " end\n"
112
+ code << "end\n"
113
+
114
+ # raise code
115
+ list = code.split("\n"); list.each_index{|x| puts((x+1).to_s.rjust(4)+": "+list[x])}
116
+ return code
117
+ end
118
+
119
+
120
+
121
+
122
+
123
+ def view_partial_code(element, varh='varh')
124
+ # send("#{element.class.name.split('::')[-1].underscore}_#{__method__}", element, varh)
125
+ special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
126
+ code = ""
127
+ partial_code = send(special_method, element, varh)
128
+ dependeds = element.dependeds.collect{|d| d[:name]}
129
+ if dependeds.size > 0
130
+ for depended in dependeds
131
+ depended_field = form.fields[depended]
132
+ code << "#{depended_field.name} = #{form.record_name}.#{depended_field.name}\n"
133
+ if depended_field.reflection
134
+ code << "#{depended_field.name} ||= #{field_datasource(depended_field)}.first\n"
135
+ end
136
+ end
137
+
138
+ code << "if #{dependeds.join(' and ')}\n"
139
+
140
+ code << partial_code.strip.gsub(/^/, ' ') << "\n"
141
+
142
+ code << "else\n"
143
+ code << " #{varh} << content_tag(:div, '', #{wrapper_attrs(element).inspect})\n"
144
+ code << "end\n"
145
+ else
146
+ code = partial_code
147
+ end
148
+ return code
149
+ end
150
+
151
+ def view_method_code(element, varh='varh')
152
+ # send("#{element.class.name.split('::')[-1].underscore}_#{__method__}", element, varh)
153
+ special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
154
+ return send(special_method, element, varh) if self.respond_to?(special_method)
155
+ code = "def #{element.prototype}\n"
156
+ code << " #{varh} = ''\n"
157
+ code << view_partial_code(element, varh).strip.gsub(/^/, ' ') << "\n"
158
+ code << " return #{varh}\n"
159
+ code << "end\n"
160
+ return code
161
+ end
162
+
163
+ def view_method_call(element, varh='varh')
164
+ special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
165
+ return send(special_method, element, varh) if self.respond_to?(special_method)
166
+ if @partials.include?(element)
167
+ return "#{varh} << #{element.prototype}\n"
168
+ else
169
+ return view_partial_code(element, varh).strip << "\n"
170
+ end
171
+ end
172
+
173
+ def wrapper_attrs(element)
174
+ html_options = (element.respond_to?(:html_options) ? element.html_options : {})
175
+ html_options[:id] = element.html_id
176
+ if @partials.include?(element)
177
+ url = {:controller => controller.controller_name.to_sym, :action=>form.action_name.to_sym, :refresh=>element.html_id}
178
+ for depended in element.dependeds
179
+ df = form.fields[depended[:name]]
180
+ url[df.input_id.to_sym] = Code.new(df.reflection.nil? ? df.name : "#{df.name}.id")
181
+ end
182
+ html_options["data-refresh"] = Code.new("url_for(#{url.inspect})")
183
+ end
184
+ special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
185
+ return send(special_method, element, html_options) if self.respond_to?(special_method)
186
+ return html_options
187
+ end
188
+
189
+ #####################################################################################
190
+ # F I E L D _ S E T M E T H O D S #
191
+ #####################################################################################
192
+
193
+ def field_set_view_partial_code(field_set, varh='varh')
194
+ # Initialize html attributes
195
+ html_options = wrapper_attrs(field_set)
196
+
197
+ varc = field_set.html_id # "field_set_#{field_set.html_id}"
198
+ code = "#{varh} << hard_content_tag(:fieldset, #{html_options.inspect}) do |#{varc}|\n"
199
+ unless field_set.title.nil?
200
+ code << " #{varc} << content_tag(:legend, ::I18n.translate('labels.#{field_set.title}'))\n"
201
+ end
202
+ for child in field_set.children
203
+ code << view_method_call(child, varc).strip.gsub(/^/, ' ') << "\n"
204
+ end
205
+ code << "end\n"
206
+ return code
207
+ end
208
+
209
+ # def field_set_view_method_code(field_set, varh='html')
210
+ # code = "def #{field_set.prototype}\n"
211
+ # code << " #{varh} = ''\n"
212
+ # code << field_set_view_partial_code(field_set, varh).strip.gsub(/^/, ' ') << "\n"
213
+ # code << " return #{varh}\n"
214
+ # code << "end\n"
215
+ # return code
216
+ # end
217
+
218
+ # def field_set_view_method_call(field_set, varh='varh')
219
+ # code = ""
220
+ # call = if @partials.include?(field_set)
221
+ # "#{varh} << #{field_set.prototype}\n"
222
+ # else
223
+ # field_set_view_partial_code(field_set, varh).strip << "\n"
224
+ # end
225
+
226
+ # if field_set.depend_on
227
+ # depended_field = form.fields[field_set.depend_on]
228
+ # code << "#{field_set.depend_on} = #{form.record_name}.#{depended_field.name}\n"
229
+ # if ref = depended_field.reflection
230
+ # code << "#{field_set.depend_on} ||= #{field_datasource(depended_field)}.first\n"
231
+ # end
232
+ # code << "if #{field_set.depend_on}\n"
233
+ # code << call.strip.gsub(/^/, ' ') << "\n"
234
+ # code << "else\n"
235
+ # opt = {:id=>field_set.html_id, :class=>"waiting", "data-refresh"=>Code.new("url_for(:controller=>:#{controller.controller_name}, :action=>:#{form.action_name}, :refresh=>'#{field_set.html_id}')")}
236
+ # code << " #{varh} << tag(:div, #{opt.inspect})\n"
237
+
238
+ # code << "end\n"
239
+ # else
240
+ # code = call
241
+ # end
242
+
243
+ # return code
244
+ # end
245
+
246
+ #####################################################################################
247
+ # F I E L D M E T H O D S #
248
+ #####################################################################################
249
+
250
+ def field_view_partial_code(field, varh='varh')
251
+ input_attrs = (field.options[:input_options].is_a?(Hash) ? field.options[:input_options] : {})
252
+ deps = form.dependents_on(field)
253
+ if deps.size > 0
254
+ input_attrs["data-dependents"] = deps.collect{|d| d.html_id}.join(',')
255
+ end
256
+
257
+ # Initialize html attributes
258
+ html_options = wrapper_attrs(field)
259
+
260
+ varc = field.html_id
261
+ code = "#{varh} << hard_content_tag(:div, #{html_options.inspect}) do |#{varc}|\n"
262
+ code << " #{varc} << label(:#{form.record_name}, :#{field.name}, nil, :class=>'attr')\n"
263
+ code << " #{form.record_name}.#{field.name} ||= #{field.default.inspect}\n" if field.default
264
+ code << self.send("field_#{field.type}_input", field, input_attrs, varc).strip.gsub(/^/, ' ') << "\n"
265
+ code << "end\n"
266
+ return code
267
+ end
268
+
269
+ # def field_view_method_code(field, varh='html')
270
+ # code = "def #{field.prototype}\n"
271
+ # code << " #{varh} = ''\n"
272
+ # code << field_view_partial_code(field, varh).strip.gsub(/^/, ' ') << "\n"
273
+ # code << " return #{varh}\n"
274
+ # code << "end\n"
275
+ # return code
276
+ # end
277
+
278
+ # def field_view_method_call(field, varh='varh')
279
+ # code = ""
280
+ # call = if @partials.include?(field)
281
+ # "#{varh} << #{field.prototype}\n"
282
+ # else
283
+ # field_view_partial_code(field, varh).strip << "\n"
284
+ # end
285
+
286
+ # if field.depend_on
287
+ # depended_field = form.fields[field.depend_on]
288
+ # code << "#{field.depend_on} = #{form.record_name}.#{depended_field.name}\n"
289
+ # code << "if #{field.depend_on}\n"
290
+ # code << call.strip.gsub(/^/, ' ') << "\n"
291
+ # code << "else\n"
292
+ # attrs = field_wrapper_attrs(field)
293
+ # attrs[:class] = "#{attrs[:class]} waiting".strip
294
+ # code << " #{varh} << tag(:div, #{attrs.inspect})\n"
295
+ # code << "end\n"
296
+ # else
297
+ # code = call
298
+ # end
299
+
300
+ # return code
301
+ # end
302
+
303
+
304
+ def field_datasource(field)
305
+ source = field.source
306
+ source = Formize.default_source unless [Array, String, Symbol].include?(source.class)
307
+ if source.is_a?(Array)
308
+ return "#{source[0]}.#{field.choices}"
309
+ elsif source == :foreign_class
310
+ return "#{field.reflection.class_name}.#{field.choices}"
311
+ elsif source == :class
312
+ return "#{form.model.name}.#{field.choices}"
313
+ else
314
+ return "#{source}.#{field.choices}"
315
+ end
316
+ end
317
+
318
+ def field_datasource_class_name(field)
319
+ source = field.source
320
+ source = Formize.default_source unless [Array, String, Symbol].include?(source.class)
321
+ if source.is_a?(Array)
322
+ return source[1]
323
+ elsif source == :foreign_class
324
+ return field.reflection.class_name
325
+ elsif source == :class
326
+ return form.model.name
327
+ else
328
+ return source.to_s.classify
329
+ end
330
+ end
331
+
332
+ def field_input_options(field)
333
+ end
334
+
335
+ def field_wrapper_attrs(field, html_options={})
336
+ html_options[:class] = "field #{html_options[:class]}".strip
337
+ html_options[:class] = "#{html_options[:class]} #{field.type.to_s.gsub('_', '-')}".strip
338
+ html_options[:class] = "#{html_options[:class]} required".strip if field.required
339
+ return html_options
340
+ end
341
+
342
+
343
+
344
+
345
+ def field_check_box_input(field, attrs={}, varc='varc')
346
+ return "#{varc} << check_box(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
347
+ end
348
+
349
+ def field_choice_input(field, attrs={}, varc='varc')
350
+ code = if field.choices.size <= Formize.radio_count_max
351
+ field_radio_input(field, attrs, varc)
352
+ else
353
+ field_select_input(field, attrs, varc)
354
+ end
355
+ return code
356
+ end
357
+
358
+ def field_date_input(field, attrs={}, varc='varc')
359
+ attrs[:size] ||= 16
360
+ return "#{varc} << date_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
361
+ end
362
+
363
+ def field_datetime_input(field, attrs={}, varc='varc')
364
+ attrs[:size] ||= 16
365
+ return "#{varc} << datetime_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
366
+ end
367
+
368
+ def field_label_input(field, attrs={}, varc='varc')
369
+ attrs[:class] = (attrs[:class]+" readonly").strip
370
+ return "#{varc} << content_tag(:span, @:#{field.record_name}.#{field.method}, #{attrs.inspect})\n"
371
+ end
372
+
373
+ def field_numeric_input(field, attrs={}, varc='varc')
374
+ attrs[:size] ||= 16
375
+ return "#{varc} << text_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
376
+ end
377
+
378
+ def field_password_input(field, attrs={}, varc='varc')
379
+ attrs[:size] ||= 24
380
+ return "#{varc} << password_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
381
+ end
382
+
383
+ def field_radio_input(field, attrs={}, varc='varc')
384
+ return "#{varc} << radio(:#{field.record_name}, :#{field.method}, #{field.choices.inspect}, #{attrs.inspect})\n"
385
+ # return "#{varc} << " << field.choices.collect{|x| "content_tag(:span, radio_button(:#{field.record_name}, :#{field.method}, #{x[1].inspect}) << ' ' << content_tag(:label, #{x[0].inspect}, :for=>'#{field.input_id}_#{x[1]}'), :class=>'rad')"}.join(" << ") << "\n"
386
+ end
387
+
388
+ def field_select_input(field, attrs={}, varc='varc')
389
+ if (include_blank = attrs.delete(:include_blank)).is_a? String
390
+ field.choices.insert(0, [include_blank, ''])
391
+ end
392
+ return "#{varc} << select(:#{field.record_name}, :#{field.method}), #{field.choices.inspect}, #{attrs.inspect})\n"
393
+ end
394
+
395
+ def field_mono_choice_input(field, attrs={}, varc='varc')
396
+ source_model = field_datasource_class_name(field).constantize
397
+ reflection = source_model.reflections[field.choices]
398
+ if reflection.nil?
399
+ raise Exception.new("#{source_model.name} must have a reflection :#{field.choices}.")
400
+ end
401
+ count = "#{field.choices}_count"
402
+ select_first_if_empty = " #{record_name}.#{field.name} ||= #{field_datasource(field)}.first\n"
403
+ code = "#{count} = #{field_datasource(field)}.count\n"
404
+ code << "if (#{count} == 0)\n"
405
+ code << field_mono_select_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
406
+ code << "elsif (#{count} <= #{Formize.radio_count_max})\n"
407
+ code << select_first_if_empty
408
+ code << field_mono_radio_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
409
+ if reflection.options[:finder_sql].nil?
410
+ code << "elsif (#{count} <= #{Formize.select_count_max})\n"
411
+ code << select_first_if_empty
412
+ code << field_mono_select_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
413
+ code << "else\n"
414
+ code << select_first_if_empty
415
+ code << field_mono_unroll_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
416
+ else
417
+ code << "else\n"
418
+ code << select_first_if_empty
419
+ code << field_mono_select_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
420
+ end
421
+ code << "end\n"
422
+
423
+ new_item_url = field.options.delete(:new)
424
+ if new_item_url.is_a? Symbol
425
+ new_item_url = {:controller=>new_item_url.to_s.pluralize.to_sym}
426
+ elsif new_item_url.is_a? TrueClass
427
+ new_item_url = {}
428
+ end
429
+
430
+ if new_item_url.is_a?(Hash)
431
+ for k, v in new_item_url
432
+ new_item_url[k] = Code.new(v) if v.is_a?(String)
433
+ end
434
+ edit_item_url = {} unless edit_item_url.is_a? Hash
435
+ if field.method.to_s.match(/_id$/) and refl = form.model.reflections[field.method.to_s[0..-4].to_sym]
436
+ new_item_url[:controller] ||= refl.class_name.underscore.pluralize
437
+ edit_item_url[:controller] ||= new_item_url[:controller]
438
+ end
439
+ new_item_url[:action] ||= :new
440
+ edit_item_url[:action] ||= :edit
441
+ data = field.options.delete(:update)||field.html_id
442
+ html_options = {"data-add-item"=>data, :class=>"icon im-new"}
443
+ code << "#{varc} << content_tag(:span, content_tag(:span, link_to(tg(:new), #{new_item_url.inspect}, #{html_options.inspect}).html_safe, :class=>:tool).html_safe, :class=>\"toolbar mini-toolbar\") if authorized?(#{new_item_url.inspect})\n"
444
+ end
445
+ return code
446
+ end
447
+
448
+ def field_mono_radio_input(field, attrs={}, varc='varc')
449
+ return "#{varc} << radio(:#{field.record_name}, :#{field.method}, #{field_datasource(field)}.collect{|item| [item.#{field.item_label}, item.id]}, {}, #{attrs.inspect})"
450
+ end
451
+
452
+ def field_mono_select_input(field, attrs={}, varc='varc')
453
+ return "#{varc} << select(:#{field.record_name}, :#{field.method}, #{field_datasource(field)}.collect{|item| [item.#{field.item_label}, item.id]}, {}, #{attrs.inspect})"
454
+ end
455
+
456
+ def field_mono_unroll_input(field, attrs={}, varc='varc')
457
+ options = {}
458
+ options[:label] ||= Code.new("Proc.new{|r| \"#{mono_choice_label(field, 'r')}\"}")
459
+ url = {:controller=>controller.controller_name, :action=>form.action_name, :unroll=>field.html_id}
460
+ for depended in field.dependeds
461
+ df = form.fields[depended[:name]]
462
+ url[df.input_id.to_sym] = Code.new(df.reflection.nil? ? df.name : "#{df.name}.id")
463
+ end
464
+ return "#{varc} << unroll(:#{field.record_name}, :#{field.method}, url_for(#{url.inspect}), #{options.inspect}, #{attrs.inspect})"
465
+ end
466
+
467
+ def field_string_input(field, attrs={}, varc='varc')
468
+ attrs[:size] ||= 24
469
+ if field.column and !field.column.limit.nil?
470
+ attrs[:size] = field.column.limit if field.column.limit<attrs[:size]
471
+ attrs[:maxlength] = field.column.limit
472
+ end
473
+ return "#{varc} << text_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
474
+ end
475
+
476
+ def field_text_area_input(field, attrs={}, varc='varc')
477
+ attrs[:cols] ||= 40
478
+ attrs[:rows] ||= 3
479
+ attrs[:class] = "#{attrs[:class]} #{attrs[:cols]==80 ? :code : nil}".strip
480
+ return "#{varc} << text_area(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
481
+ end
482
+
483
+
484
+
485
+
486
+
487
+
488
+ protected
489
+
490
+ def sanitize_conditions(value)
491
+ if value.is_a? Array
492
+ if value.size==1 and value[0].is_a? String
493
+ value[0].to_s
494
+ else
495
+ value.inspect
496
+ end
497
+ elsif value.is_a? String
498
+ '"'+value.gsub('"','\"')+'"'
499
+ elsif [Date, DateTime].include? value.class
500
+ '"'+value.to_formatted_s(:db)+'"'
501
+ else
502
+ value.to_s
503
+ end
504
+ end
505
+
506
+
507
+ def mono_choice_label(choice, varr='record')
508
+ return "\#\{#{varr}.#{choice.item_label}\}"
509
+ end
510
+
511
+ def mono_choice_search_code(field)
512
+ source_model = field_datasource_class_name(field).constantize
513
+ reflection = source_model.reflections[field.choices]
514
+ if reflection.nil?
515
+ raise Exception.new("#{source_model.name} must have a reflection :#{field.choices}.")
516
+ end
517
+ model = reflection.class_name.constantize
518
+ foreign_record = model.name.underscore
519
+ foreign_records = "#{source_model.name.underscore}_#{field.choices}"
520
+ options = field.options
521
+ attributes = field.search_attributes
522
+ attributes = [attributes] unless attributes.is_a? Array
523
+ attributes_hash = {}
524
+ attributes.each_index do |i|
525
+ attribute = attributes[i]
526
+ attributes[i] = [
527
+ (attribute.to_s.match(/\./) ? attribute.to_s : model.table_name+'.'+attribute.to_s.split(/\:/)[0]),
528
+ (attribute.to_s.match(/\:/) ? attribute.to_s.split(/\:/)[1] : (options[:filter]||'%X%')),
529
+ '_a'+i.to_s]
530
+ attributes_hash[attributes[i][2]] = attributes[i][0]
531
+ end
532
+ query = []
533
+ parameters = ''
534
+ if options[:conditions].is_a? Hash
535
+ options[:conditions].each do |key, value|
536
+ query << (key.is_a?(Symbol) ? model.table_name+"."+key.to_s : key.to_s)+'=?'
537
+ parameters += ', ' + sanitize_conditions(value)
538
+ end
539
+ elsif options[:conditions].is_a? Array
540
+ conditions = options[:conditions]
541
+ case conditions[0]
542
+ when String # SQL
543
+ # query << '["'+conditions[0].to_s+'"'
544
+ query << conditions[0].to_s
545
+ parameters += ', '+conditions[1..-1].collect{|p| sanitize_conditions(p)}.join(', ') if conditions.size>1
546
+ # query << ')'
547
+ else
548
+ raise Exception.new("First element of an Array can only be String or Symbol.")
549
+ end
550
+ end
551
+
552
+ select = (model.table_name+".id AS id, "+attributes_hash.collect{|k,v| v+" AS "+k}.join(", ")).inspect
553
+ joins = options[:joins] ? ", :joins=>"+options[:joins].inspect : ""
554
+
555
+ code = ""
556
+ code << "conditions = [#{query.join(' AND ').inspect+parameters}]\n"
557
+ code << "search = params[:search]\n"
558
+ code << "words = search.lower.split(/[\\s\\,]+/)\n"
559
+ code << "if words.size > 0\n"
560
+ code << " conditions[0] << '#{' AND ' if query.size>0}('\n"
561
+ code << " words.each_index do |index|\n"
562
+ code << " word = words[index].to_s\n"
563
+ code << " conditions[0] << ') AND (' if index > 0\n"
564
+
565
+ if ActiveRecord::Base.connection.adapter_name == "MySQL"
566
+ code << " conditions[0] << "+attributes.collect{|key| "LOWER(CAST(#{key[0]} AS CHAR)) LIKE ?"}.join(' OR ').inspect+"\n"
567
+ else
568
+ code << " conditions[0] << "+attributes.collect{|key| "LOWER(CAST(#{key[0]} AS VARCHAR)) LIKE ?"}.join(' OR ').inspect+"\n"
569
+ end
570
+
571
+ code << " conditions += ["+attributes.collect{|key| key[1].inspect.gsub('X', '"+word+"').gsub(/(^\"\"\+|\+\"\"\+|\+\"\")/, '')}.join(", ")+"]\n"
572
+ code << " end\n"
573
+ code << " conditions[0] << ')'\n"
574
+ code << "end\n"
575
+ order = ", :order=>"+attributes.collect{|key| "#{key[0]} ASC"}.join(', ').inspect
576
+ limit = ", :limit=>"+(options[:limit]||12).to_s
577
+ partial = options[:partial]
578
+
579
+ html = "<ul><%for #{foreign_record} in #{foreign_records}-%><li id='<%=#{foreign_record}.id-%>'>"
580
+ html << "<%content=#{foreign_record}.#{field.item_label}-%>"
581
+ # html << "<%content="+attributes.collect{|key| "#{foreign_record}['#{key[2]}'].to_s"}.join('+", "+')+" -%>"
582
+ if partial
583
+ html << "<%=render(:partial=>#{partial.inspect}, :locals =>{:#{foreign_record}=>#{foreign_record}, :content=>content, :search=>search})-%>"
584
+ else
585
+ html << "<%=highlight(content, search)-%>"
586
+ end
587
+ html << '</li><%end-%></ul>'
588
+
589
+ code << "#{foreign_records} = #{field_datasource(field)}.find(:all, :conditions=>conditions"+joins+order+limit+")\n"
590
+ code << "render :inline=>#{html.inspect}, :locals=>{:#{foreign_records}=>#{foreign_records}, :search=>search}\n"
591
+ return code
592
+ end
593
+
594
+
595
+
596
+ end
597
+
598
+ end
data/lib/formize.rb ADDED
@@ -0,0 +1,34 @@
1
+ # Formize provides controller's side defined forms.
2
+ module Formize
3
+
4
+ def self.configure(name, value = nil)
5
+ unless self.respond_to?("#{name}=")
6
+ mattr_accessor(name)
7
+ self.send("#{name}=", value)
8
+ end
9
+ end
10
+
11
+ # default_source used by mono_choices:
12
+ # - :foreign_class : Class of foreign object
13
+ # - :class : Class of object
14
+ # - "variable_name" or :variable_name : A variable (Class name is computed with the name
15
+ # of the variable. Example: "product" will have "Product" class_name. If class_name
16
+ # has to be different, use next possibility.
17
+ # - ["variable_name", "class_name"] : Code used to select source with the
18
+ # class_name of the variable.
19
+ configure :default_source, :foreign_class
20
+
21
+ # How many radio can be displayed before to become a +select+
22
+ configure :radio_count_max, 3
23
+
24
+ # How many select options can be displayed before to become a +unroll+
25
+ configure :select_count_max, 7
26
+
27
+ end
28
+
29
+ require 'action_view'
30
+ require 'formize/definition'
31
+ require 'formize/generator'
32
+ require 'formize/form_helper'
33
+ require 'formize/action_pack'
34
+
data/test/helper.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ require 'formize'
7
+
8
+ class Test::Unit::TestCase
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestFormize < Test::Unit::TestCase
4
+ def test_something_for_real
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end