active_form 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. data.tar.gz.sig +2 -0
  2. data/History.txt +4 -0
  3. data/License.txt +20 -0
  4. data/MIT-LICENSE +19 -0
  5. data/Manifest.txt +181 -0
  6. data/README.txt +1 -0
  7. data/Rakefile +4 -0
  8. data/config/hoe.rb +71 -0
  9. data/config/requirements.rb +17 -0
  10. data/init.rb +5 -0
  11. data/lib/active_form.rb +86 -0
  12. data/lib/active_form/core_extensions.rb +179 -0
  13. data/lib/active_form/definition.rb +72 -0
  14. data/lib/active_form/element.rb +50 -0
  15. data/lib/active_form/elements/base.rb +67 -0
  16. data/lib/active_form/elements/builder.rb +103 -0
  17. data/lib/active_form/elements/button.rb +15 -0
  18. data/lib/active_form/elements/checkbox.rb +18 -0
  19. data/lib/active_form/elements/file.rb +15 -0
  20. data/lib/active_form/elements/hidden.rb +9 -0
  21. data/lib/active_form/elements/image.rb +7 -0
  22. data/lib/active_form/elements/input.rb +23 -0
  23. data/lib/active_form/elements/password.rb +12 -0
  24. data/lib/active_form/elements/radio.rb +18 -0
  25. data/lib/active_form/elements/reset.rb +15 -0
  26. data/lib/active_form/elements/section.rb +37 -0
  27. data/lib/active_form/elements/select.rb +42 -0
  28. data/lib/active_form/elements/submit.rb +19 -0
  29. data/lib/active_form/elements/text.rb +9 -0
  30. data/lib/active_form/elements/textarea.rb +18 -0
  31. data/lib/active_form/errors.rb +73 -0
  32. data/lib/active_form/facets/checkbox_group.rb +11 -0
  33. data/lib/active_form/facets/collection_input.rb +96 -0
  34. data/lib/active_form/facets/radio_group.rb +11 -0
  35. data/lib/active_form/facets/select_date.rb +10 -0
  36. data/lib/active_form/facets/select_datetime.rb +10 -0
  37. data/lib/active_form/facets/select_day.rb +17 -0
  38. data/lib/active_form/facets/select_from_model.rb +60 -0
  39. data/lib/active_form/facets/select_hour.rb +17 -0
  40. data/lib/active_form/facets/select_minute.rb +17 -0
  41. data/lib/active_form/facets/select_month.rb +46 -0
  42. data/lib/active_form/facets/select_numeric_range.rb +59 -0
  43. data/lib/active_form/facets/select_second.rb +17 -0
  44. data/lib/active_form/facets/select_time.rb +10 -0
  45. data/lib/active_form/facets/select_timebased.rb +145 -0
  46. data/lib/active_form/facets/select_weekday.rb +46 -0
  47. data/lib/active_form/facets/select_year.rb +24 -0
  48. data/lib/active_form/mixins/attribute_methods.rb +33 -0
  49. data/lib/active_form/mixins/casting.rb +152 -0
  50. data/lib/active_form/mixins/collection_element_methods.rb +204 -0
  51. data/lib/active_form/mixins/common_methods.rb +350 -0
  52. data/lib/active_form/mixins/container_methods.rb +417 -0
  53. data/lib/active_form/mixins/css_methods.rb +70 -0
  54. data/lib/active_form/mixins/element_methods.rb +314 -0
  55. data/lib/active_form/mixins/javascript_methods.rb +99 -0
  56. data/lib/active_form/mixins/loader_methods.rb +72 -0
  57. data/lib/active_form/mixins/option_element_methods.rb +61 -0
  58. data/lib/active_form/mixins/validation_methods.rb +253 -0
  59. data/lib/active_form/validator.rb +47 -0
  60. data/lib/active_form/validators/alpha.rb +9 -0
  61. data/lib/active_form/validators/alphanum.rb +9 -0
  62. data/lib/active_form/validators/base.rb +132 -0
  63. data/lib/active_form/validators/digits.rb +9 -0
  64. data/lib/active_form/validators/email.rb +29 -0
  65. data/lib/active_form/validators/format.rb +15 -0
  66. data/lib/active_form/validators/length_range.rb +24 -0
  67. data/lib/active_form/validators/number.rb +9 -0
  68. data/lib/active_form/validators/option_count.rb +24 -0
  69. data/lib/active_form/validators/proc.rb +22 -0
  70. data/lib/active_form/validators/required.rb +9 -0
  71. data/lib/active_form/validators/set.rb +21 -0
  72. data/lib/active_form/validators/time_range.rb +30 -0
  73. data/lib/active_form/validators/uri.rb +54 -0
  74. data/lib/active_form/version.rb +9 -0
  75. data/lib/active_form/views/fieldsets.rb +34 -0
  76. data/lib/active_form/views/plain.rb +32 -0
  77. data/lib/active_form/views/tables.rb +28 -0
  78. data/lib/active_form/widget.rb +43 -0
  79. data/lib/active_form/widgets/base.rb +28 -0
  80. data/lib/loob/uri_validator.rb +140 -0
  81. data/lib/rails/acts_as_dropdown/MIT-LICENSE +20 -0
  82. data/lib/rails/acts_as_dropdown/acts_as_dropdown.rb +119 -0
  83. data/lib/rails/acts_as_dropdown/dropdown.rb +27 -0
  84. data/lib/rails/controller_helper.rb +19 -0
  85. data/lib/rails/model/loader.rb +206 -0
  86. data/lib/rails/view_helper.rb +20 -0
  87. data/samples/html/css/style.css +175 -0
  88. data/samples/html/js/effects.js +958 -0
  89. data/samples/html/js/prototype.js +2006 -0
  90. data/samples/html/js/validation.js +228 -0
  91. data/samples/html/plain_view.html +77 -0
  92. data/samples/html/sample001.html +158 -0
  93. data/samples/html/sample002.html +76 -0
  94. data/samples/html/sample003.html +34 -0
  95. data/samples/layouts/default.rhtml +18 -0
  96. data/samples/layouts/plain.rhtml +21 -0
  97. data/samples/layouts/sample003.rhtml +25 -0
  98. data/samples/plain_view.rb +58 -0
  99. data/samples/sample001.rb +111 -0
  100. data/samples/sample002.rb +92 -0
  101. data/samples/sample003.rb +30 -0
  102. data/script/destroy +14 -0
  103. data/script/generate +14 -0
  104. data/script/txt2html +74 -0
  105. data/setup.rb +1585 -0
  106. data/tasks/deployment.rake +34 -0
  107. data/tasks/environment.rake +7 -0
  108. data/tasks/website.rake +17 -0
  109. data/test/elements/test_base_element.rb +159 -0
  110. data/test/elements/test_builder_element.rb +81 -0
  111. data/test/elements/test_button_element.rb +12 -0
  112. data/test/elements/test_checkbox_element.rb +233 -0
  113. data/test/elements/test_file_element.rb +20 -0
  114. data/test/elements/test_hidden_element.rb +11 -0
  115. data/test/elements/test_image_element.rb +11 -0
  116. data/test/elements/test_input_element.rb +39 -0
  117. data/test/elements/test_password_element.rb +16 -0
  118. data/test/elements/test_radio_element.rb +197 -0
  119. data/test/elements/test_reset_element.rb +12 -0
  120. data/test/elements/test_section_element.rb +162 -0
  121. data/test/elements/test_select_element.rb +364 -0
  122. data/test/elements/test_submit_element.rb +12 -0
  123. data/test/elements/test_text_element.rb +91 -0
  124. data/test/elements/test_textarea_element.rb +23 -0
  125. data/test/facets/test_checkbox_group_element.rb +388 -0
  126. data/test/facets/test_radio_group_element.rb +312 -0
  127. data/test/facets/test_select_date_element.rb +211 -0
  128. data/test/facets/test_select_datetime_element.rb +56 -0
  129. data/test/facets/test_select_day_element.rb +37 -0
  130. data/test/facets/test_select_from_model_element.rb +86 -0
  131. data/test/facets/test_select_hour_element.rb +37 -0
  132. data/test/facets/test_select_minute_element.rb +52 -0
  133. data/test/facets/test_select_month_element.rb +79 -0
  134. data/test/facets/test_select_numeric_range_element.rb +14 -0
  135. data/test/facets/test_select_second_element.rb +48 -0
  136. data/test/facets/test_select_time_element.rb +148 -0
  137. data/test/facets/test_select_weekday_element.rb +71 -0
  138. data/test/facets/test_select_year_element.rb +73 -0
  139. data/test/fixtures/author.rb +11 -0
  140. data/test/fixtures/authors.yml +0 -0
  141. data/test/fixtures/book.rb +14 -0
  142. data/test/fixtures/books.yml +8 -0
  143. data/test/fixtures/categories.yml +0 -0
  144. data/test/fixtures/categorization.rb +2 -0
  145. data/test/fixtures/categorizations.yml +0 -0
  146. data/test/fixtures/category.rb +8 -0
  147. data/test/fixtures/publisher.rb +5 -0
  148. data/test/fixtures/publishers.yml +10 -0
  149. data/test/fixtures/schema.rb +43 -0
  150. data/test/rails/test_model_autodefinition.rb +121 -0
  151. data/test/rails/test_model_loader.rb +61 -0
  152. data/test/resources/elements/chunky.rb +11 -0
  153. data/test/resources/forms/demo.rb +5 -0
  154. data/test/resources/models/book.rb +8 -0
  155. data/test/resources/models/register_publisher.rb +5 -0
  156. data/test/resources/sections/demo.rb +6 -0
  157. data/test/resources/sections/foo.rb +6 -0
  158. data/test/resources/validators/foo.rb +9 -0
  159. data/test/resources/widgets/custom.rb +13 -0
  160. data/test/test_active_form.rb +1050 -0
  161. data/test/test_casting.rb +124 -0
  162. data/test/test_definition.rb +68 -0
  163. data/test/test_definition_class.rb +118 -0
  164. data/test/test_element_class.rb +201 -0
  165. data/test/test_helper.rb +74 -0
  166. data/test/test_javascript.rb +234 -0
  167. data/test/test_load_definition.rb +68 -0
  168. data/test/test_load_element.rb +35 -0
  169. data/test/test_load_section_element.rb +43 -0
  170. data/test/test_load_validator.rb +31 -0
  171. data/test/test_load_widget.rb +93 -0
  172. data/test/test_validation.rb +722 -0
  173. data/test/validators/test_validates_as_alpha.rb +26 -0
  174. data/test/validators/test_validates_as_alphanum.rb +26 -0
  175. data/test/validators/test_validates_as_digits.rb +26 -0
  176. data/test/validators/test_validates_as_email.rb +29 -0
  177. data/test/validators/test_validates_as_number.rb +26 -0
  178. data/test/validators/test_validates_as_uri.rb +128 -0
  179. data/test/validators/test_validates_with_format.rb +26 -0
  180. data/test/validators/test_validates_within_length_range.rb +46 -0
  181. data/test/validators/test_validates_within_set.rb +46 -0
  182. data/test/validators/test_validates_within_time_range.rb +53 -0
  183. metadata +307 -0
  184. metadata.gz.sig +4 -0
@@ -0,0 +1,17 @@
1
+ ActiveForm::Element::SelectNumericRange::create :select_minute do
2
+
3
+ def range
4
+ (0..59)
5
+ end
6
+
7
+ def casting_filter(value)
8
+ value = case value
9
+ when Date then value.to_time.min
10
+ when Time then value.min
11
+ when Array, Range then value.to_a
12
+ else value.to_i rescue 0
13
+ end
14
+ super(value)
15
+ end
16
+
17
+ end
@@ -0,0 +1,46 @@
1
+ ActiveForm::Element::SelectNumericRange::create :select_month do
2
+
3
+ define_option_flags :use_short_month, :add_month_numbers, :use_month_numbers
4
+
5
+ def to_monthname
6
+ multiple? ? element_value.map { |i| number_to_label(i) } : number_to_label(element_value)
7
+ end
8
+
9
+ def export_value
10
+ exp_value = super
11
+ if self.type_cast == :string
12
+ to_monthname
13
+ else
14
+ exp_value
15
+ end
16
+ end
17
+
18
+ def range
19
+ (1..12)
20
+ end
21
+
22
+ def casting_for_string
23
+ [nil, nil]
24
+ end
25
+
26
+ def casting_filter(value)
27
+ value = case value
28
+ when Date, Time then value.month
29
+ when Array, Range then value.to_a
30
+ else value.to_i rescue 0
31
+ end
32
+ super(value)
33
+ end
34
+
35
+ def number_to_label(month_number)
36
+ month_names = use_short_month? ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES rescue {}
37
+ if use_month_numbers? || month_names.empty?
38
+ month_number.zero_padded(2)
39
+ elsif add_month_numbers?
40
+ month_number.zero_padded(2) + ' - ' + month_names[month_number]
41
+ else
42
+ month_names[month_number]
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,59 @@
1
+ ActiveForm::Element::Select::create :select_numeric_range do
2
+
3
+ attr_accessor :increment, :range, :subset
4
+
5
+ def casting_filter(value)
6
+ multiple? && value.respond_to?(:map) ? value.map { |val| normalize_value(val) } : normalize_value(value)
7
+ end
8
+
9
+ def element_value
10
+ v = [*super].compact.map { |val| normalize_value(val) }.uniq
11
+ multiple? ? v : v.first
12
+ end
13
+ alias :values :element_value
14
+ alias :value :element_value
15
+
16
+ def normalize_value(value)
17
+ integer = value.respond_to?(:to_i) ? value.to_i : 0
18
+ valid_opts = self.option_values
19
+ incr = (self.increment || 1)
20
+ min_value = self.range.first
21
+ max_value = self.range.last
22
+ min = min_value.nearest(incr)
23
+ min = min + incr if min < min_value && incr > 1
24
+ max = max_value.nearest(incr)
25
+ max = max - incr if max > max_value && incr > 1
26
+ if valid_opts.include?(integer)
27
+ val = integer
28
+ else
29
+ val = integer.nearest(incr)
30
+ if val > min && val < max && !valid_opts.include?(val)
31
+ val = valid_opts.detect { |v| v >= integer }
32
+ end
33
+ end
34
+ (val > min_value ? (val > max_value ? max : val) : min)
35
+ end
36
+
37
+ def options
38
+ opts = []
39
+ opts << ActiveForm::Element::CollectionOption.new('--', :blank) if include_empty?
40
+ option_range = self.subset.kind_of?(Array) ? self.subset & self.range.to_a : self.range
41
+ if self.increment > 1 && self.range.kind_of?(Range)
42
+ (option_range).step(self.increment) { |i| opts << ActiveForm::Element::CollectionOption.new(number_to_label(i), i) }
43
+ else
44
+ option_range.to_a.each { |i| opts << ActiveForm::Element::CollectionOption.new(number_to_label(i), i) }
45
+ end
46
+ opts
47
+ end
48
+
49
+ def number_to_label(i)
50
+ i.zero_padded(2)
51
+ end
52
+
53
+ def update_options_and_attributes(hash)
54
+ self.increment = hash.delete(:increment) || hash.delete('increment') || 1
55
+ self.range = hash.delete(:range) || hash.delete('range') unless self.range.blank?
56
+ super(hash)
57
+ end
58
+
59
+ end
@@ -0,0 +1,17 @@
1
+ ActiveForm::Element::SelectNumericRange::create :select_second do
2
+
3
+ def range
4
+ (0..59)
5
+ end
6
+
7
+ def casting_filter(value)
8
+ value = case value
9
+ when Date then value.to_time.sec
10
+ when Time then value.sec
11
+ when Array, Range then value.to_a
12
+ else value.to_i rescue 0
13
+ end
14
+ super(value)
15
+ end
16
+
17
+ end
@@ -0,0 +1,10 @@
1
+ class ActiveForm::Element::SelectTime < ActiveForm::Element::SelectTimebased
2
+
3
+ self.default_format = [:hour, :minute]
4
+ self.allowed_parts = [:hour, :minute, :second]
5
+
6
+ def self.element_type
7
+ :select_time
8
+ end
9
+
10
+ end
@@ -0,0 +1,145 @@
1
+ class ActiveForm::Element::SelectTimebased < ActiveForm::Element::Section
2
+
3
+ TIME_FORMAT = [:year, :month, :day, :hour, :minute, :second].freeze
4
+ DEFAULT_VALUES = { :year => 2000, :month => 1, :day => 1, :hour => 12, :minute => 0, :second => 0 }.freeze
5
+ VALUE_CALL_MAP = { :year => :year, :month => :month, :day => :day, :hour => :hour, :minute => :min, :second => :sec }.freeze
6
+
7
+ def self.inherited(derivative)
8
+ super
9
+ derivative.class_inheritable_accessor :default_format
10
+ derivative.class_inheritable_accessor :allowed_parts
11
+ derivative.default_format = TIME_FORMAT
12
+ derivative.allowed_parts = TIME_FORMAT
13
+ end
14
+
15
+ class_inheritable_accessor :default_format
16
+ class_inheritable_accessor :allowed_parts
17
+ self.default_format = TIME_FORMAT
18
+ self.allowed_parts = TIME_FORMAT
19
+
20
+ attr_reader :now
21
+ attr_accessor :format
22
+ attr_accessor :start_year, :end_year, :range
23
+
24
+ attr_accessor :year_label, :month_label, :day_label
25
+ attr_accessor :year_increment, :month_increment, :day_increment
26
+
27
+ attr_accessor :hour_label, :minute_label, :second_label
28
+ attr_accessor :hour_increment, :minute_increment, :second_increment
29
+
30
+ def self.element_type
31
+ :select_timebased
32
+ end
33
+
34
+ def now=(value)
35
+ @now = case value
36
+ when Date then value.to_time
37
+ when Time then value
38
+ else nil
39
+ end
40
+ end
41
+
42
+ def render_element(builder = create_builder)
43
+ builder.div(element_attributes) { render_elements(builder) }
44
+ end
45
+
46
+ def include_empty=(bool = true)
47
+ self.update_elements(:include_empty => bool)
48
+ end
49
+ alias :include_empty :include_empty=
50
+
51
+ def update_from_params(params, force = false)
52
+ super(casting_filter(params), force)
53
+ end
54
+
55
+ alias :original_export_value :export_value
56
+
57
+ def export_value(values = ActiveForm::Values.new)
58
+ export_value_as(self.type_cast)
59
+ end
60
+
61
+ def export_value_as(type)
62
+ cast_value_to(original_export_value, type)
63
+ end
64
+
65
+ def cast_value_to(value, type = :string)
66
+ if [:date, :time, :hash, :array, :string, :yaml].include?(type)
67
+ time_hash = default_element_values.merge(time_to_values(self.now, true)).merge(value)
68
+ (self.class.allowed_parts - elements_format).each { |part| time_hash[part] = 0 }
69
+ return time_hash if type == :hash
70
+ time_array = TIME_FORMAT.collect { |part| time_hash[part] || 0 }
71
+ return time_array if type == :array
72
+ time = Time.send(ActiveForm::Element::Base.default_timezone, *time_array) rescue nil
73
+ return time.to_date if type == :date && time.respond_to?(:to_date)
74
+ return time.to_formatted_s(:db) if type == :string && time.respond_to?(:to_formatted_s)
75
+ return time.to_yaml if type == :yaml
76
+ time
77
+ else
78
+ value
79
+ end
80
+ end
81
+
82
+ def type_cast=(type = :string)
83
+ @type_cast = type.to_sym
84
+ end
85
+
86
+ def casting_filter(value)
87
+ time = case value
88
+ when Date then value.to_time
89
+ when Time then value
90
+ when String then self.class.string_to_time(value)
91
+ when Hash then return ActiveForm::Values.new(value)
92
+ else nil
93
+ end
94
+ return default_element_values if time.nil?
95
+ time_to_values(time)
96
+ end
97
+
98
+ def after_initialize
99
+ elements_format.each do |part|
100
+ if self.class.allowed_parts.include?(part)
101
+ defaults = {}
102
+ defaults[:label] = self.send("#{part}_label") rescue part.to_s
103
+ defaults[:increment] = self.send("#{part}_increment") || 1 rescue 1
104
+ if part == :year
105
+ defaults[:range] = self.range if self.range.kind_of?(Range)
106
+ defaults[:start_year] = self.start_year if self.start_year.kind_of?(Integer)
107
+ defaults[:end_year] = self.end_year if self.end_year.kind_of?(Integer)
108
+ end
109
+ self.define_element("select_#{part}", "#{part}", defaults) do |e|
110
+ e.define_element_wrapper do |builder, elem, render|
111
+ builder.span(:id => "elem_#{elem.identifier}", :class => elem.css, :style => elem.style) { render.call(builder) }
112
+ end
113
+ end
114
+ elsif !part.kind_of?(Symbol)
115
+ self << part
116
+ end
117
+ end
118
+ update_values(default_element_values)
119
+ end
120
+
121
+ private
122
+
123
+ def elements_format
124
+ (self.format || self.class.default_format)
125
+ end
126
+
127
+ def default_element_values
128
+ (elements_format & self.class.allowed_parts).inject(ActiveForm::Values.new) do |values, part|
129
+ values[part] = default_value_for(part)
130
+ values
131
+ end
132
+ end
133
+
134
+ def time_to_values(time, all = false)
135
+ (all ? TIME_FORMAT : (elements_format & self.class.allowed_parts)).inject(ActiveForm::Values.new) do |values, part|
136
+ values[part] = time.send(VALUE_CALL_MAP[part]) if time.respond_to?(VALUE_CALL_MAP[part])
137
+ values
138
+ end
139
+ end
140
+
141
+ def default_value_for(part)
142
+ (now.kind_of?(Time) && now.respond_to?(VALUE_CALL_MAP[part]) ? now.send(VALUE_CALL_MAP[part]) : DEFAULT_VALUES[part].to_i) rescue 0
143
+ end
144
+
145
+ end
@@ -0,0 +1,46 @@
1
+ ActiveForm::Element::SelectNumericRange::create :select_weekday do
2
+
3
+ define_option_flags :use_short_day, :weekend_only, :weekdays_only
4
+
5
+ def to_dayname
6
+ multiple? ? element_value.map { |i| number_to_label(i) } : number_to_label(element_value)
7
+ end
8
+
9
+ def export_value
10
+ exp_value = super
11
+ if self.type_cast == :string
12
+ to_dayname
13
+ else
14
+ exp_value
15
+ end
16
+ end
17
+
18
+ def range
19
+ if weekend_only?
20
+ [6, 0]
21
+ elsif weekdays_only?
22
+ (1..5)
23
+ else
24
+ (0..6)
25
+ end
26
+ end
27
+
28
+ def casting_for_string
29
+ [nil, nil]
30
+ end
31
+
32
+ def casting_filter(value)
33
+ value = case value
34
+ when Date, Time then value.wday
35
+ when Array, Range then value.to_a
36
+ else value.to_i rescue 0
37
+ end
38
+ super(value)
39
+ end
40
+
41
+ def number_to_label(day_number)
42
+ day_names = use_short_day? ? Date::ABBR_DAYNAMES : Date::DAYNAMES rescue {}
43
+ day_names[day_number]
44
+ end
45
+
46
+ end
@@ -0,0 +1,24 @@
1
+ ActiveForm::Element::SelectNumericRange::create :select_year do
2
+
3
+ def range
4
+ @range ||= Range.new(Time.now.year - 5, Time.now.year + 5)
5
+ end
6
+
7
+ def start_year=(int)
8
+ @range = Range.new(int.to_i, self.range.last)
9
+ end
10
+
11
+ def end_year=(int)
12
+ @range = Range.new(self.range.first, int.to_i)
13
+ end
14
+
15
+ def casting_filter(value)
16
+ value = case value
17
+ when Date, Time then value.year
18
+ when Array, Range then value.to_a
19
+ else value.to_i rescue 0
20
+ end
21
+ super(value)
22
+ end
23
+
24
+ end
@@ -0,0 +1,33 @@
1
+ module ActiveForm::Mixins::AttributeMethods
2
+
3
+ def self.included(base)
4
+ [:type].each { |m| base.send(:undef_method, m) rescue nil }
5
+ base.send(:extend, ClassMethods)
6
+ end
7
+
8
+ def attributes
9
+ @attributes ||= HashWithIndifferentAccess.new
10
+ end
11
+
12
+ def default_attributes
13
+ { :id => identifier, :class => css }
14
+ end
15
+
16
+ def attribute_names
17
+ [:style, :javascript, :title, :lang] + self.class.element_attribute_names.to_a
18
+ end
19
+
20
+ module ClassMethods
21
+
22
+ def define_attributes(*attrs)
23
+ attrs.push(:lang) unless self.element_attribute_names.include?(:lang)
24
+ attrs.flatten.each do |attribute|
25
+ self.element_attribute_names += [attribute.to_sym]
26
+ define_method("#{attribute}=") { |value| attributes[attribute] = value } unless instance_methods.include?("#{attribute}=")
27
+ define_method("#{attribute}") { attributes[attribute] } unless instance_methods.include?("#{attribute}")
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,152 @@
1
+ module ActiveForm
2
+ module Mixins
3
+ module Casting
4
+
5
+ def self.included(base)
6
+ base.send(:extend, ClassMethods)
7
+ base.send(:attr_reader, :type_cast)
8
+ end
9
+
10
+ def cast_value(value)
11
+ if self.respond_to?(:casting_filter)
12
+ self.casting_filter(value)
13
+ elsif self.class.respond_to?(:casting_filter)
14
+ self.class.casting_filter(value)
15
+ else
16
+ value
17
+ end
18
+ end
19
+
20
+ def type_cast=(type = :string)
21
+ if self.respond_to?("casting_for_#{type}")
22
+ @type_cast = type.to_sym
23
+ cast, intern = self.send("casting_for_#{type}")
24
+ define_casting_filter(cast) if cast
25
+ define_formatting_filter(intern) if intern
26
+ end
27
+ end
28
+
29
+ def casting_for_string
30
+ [lambda { |value| value.is_a?(String) ? value : value.to_s }, nil]
31
+ end
32
+ alias :casting_for_text :casting_for_string
33
+
34
+ def casting_for_integer
35
+ [lambda { |value| value.is_a?(Integer) ? value : value.to_i rescue value ? 1 : 0 }, nil]
36
+ end
37
+
38
+ def casting_for_yaml
39
+ [self.class.method_to_proc(:yaml_to_data), self.class.method_to_proc(:data_to_yaml)]
40
+ end
41
+
42
+ def casting_for_float
43
+ [lambda { |value| value.is_a?(Float) ? value : value.to_f rescue 0 }, nil]
44
+ end
45
+
46
+ def casting_for_array
47
+ [lambda { |value| value.is_a?(Array) ? value : [*value] }, lambda { |value| [*value].join(', ') }]
48
+ end
49
+
50
+ def casting_for_datetime
51
+ [self.class.method_to_proc(:string_to_time), self.class.method_to_proc(:time_to_string)]
52
+ end
53
+ alias :casting_for_timestamp :casting_for_datetime
54
+
55
+ def casting_for_time
56
+ [self.class.method_to_proc(:string_to_dummy_time), self.class.method_to_proc(:time_to_string)]
57
+ end
58
+
59
+ def casting_for_date
60
+ [self.class.method_to_proc(:string_to_date), self.class.method_to_proc(:date_to_string)]
61
+ end
62
+
63
+ def casting_for_boolean
64
+ [self.class.method_to_proc(:value_to_boolean), self.class.method_to_proc(:boolean_to_value)]
65
+ end
66
+
67
+ def define_casting_filter(prc = nil, &block)
68
+ define_singleton_method(:casting_filter, &(block_given? ? block : prc))
69
+ end
70
+ alias :casting_filter= :define_casting_filter
71
+
72
+ def reset_casting_filter
73
+ define_singleton_method(:casting_filter) rescue nil
74
+ end
75
+
76
+ module ClassMethods
77
+
78
+ def define_casting_filter(prc = nil, &block)
79
+ define_singleton_method(:casting_filter, &(block_given? ? block : prc))
80
+ end
81
+ alias :casting_filter= :define_casting_filter
82
+
83
+ def reset_casting_filter
84
+ define_singleton_method(:casting_filter) rescue nil
85
+ end
86
+
87
+ # type casting methods
88
+
89
+ def binary_to_string(value)
90
+ value
91
+ end
92
+
93
+ def data_to_yaml(value)
94
+ value.to_yaml
95
+ end
96
+
97
+ def yaml_to_data(value)
98
+ return value unless value.is_a?(String)
99
+ YAML::load(value) rescue nil
100
+ end
101
+
102
+ def string_to_date(string)
103
+ return string unless string.is_a?(String)
104
+ date_array = ParseDate.parsedate(string)
105
+ # treat 0000-00-00 as nil
106
+ Date.new(date_array[0], date_array[1], date_array[2]) rescue nil
107
+ end
108
+
109
+ def date_to_string(date)
110
+ date.respond_to?(:to_formatted_s) ? date.to_formatted_s(:long) : date.to_s
111
+ end
112
+
113
+ def string_to_time(string)
114
+ return string unless string.is_a?(String)
115
+ if string.strip.match(/^(\d{1,2})[:\.](\d{1,2})([:\.](\d{1,2}))?$/)
116
+ current_time = Time.now
117
+ string = "#{current_time.year}-#{current_time.month}-#{current_time.day} #{string}"
118
+ end
119
+ # treat 0000-00-00 00:00:00 as nil
120
+ time_array = ParseDate.parsedate(string)[0..5]
121
+ Time.send(ActiveForm::Element::Base.default_timezone, *time_array) rescue nil
122
+ end
123
+
124
+ def time_to_string(time)
125
+ time.respond_to?(:to_formatted_s) ? time.to_formatted_s(:long) : time.to_s
126
+ end
127
+
128
+ def string_to_dummy_time(string)
129
+ return string unless string.is_a?(String)
130
+ time_array = ParseDate.parsedate(string)
131
+ # pad the resulting array with dummy date information
132
+ time_array[0] = 2000; time_array[1] = 1; time_array[2] = 1;
133
+ Time.send(ActiveForm::Element::Base.default_timezone, *time_array) rescue nil
134
+ end
135
+
136
+ def value_to_boolean(value)
137
+ return value if value==true || value==false
138
+ case value.to_s.downcase
139
+ when "true", "t", "1" then true
140
+ else false
141
+ end
142
+ end
143
+
144
+ def boolean_to_value(boolean)
145
+ boolean ? "true" : "false"
146
+ end
147
+
148
+ end
149
+
150
+ end
151
+ end
152
+ end