active_form 0.0.1

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 (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