amount_field 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ == 1.4.0 2009-10-06
2
+
3
+ * fix: negative values like '-1,00', '-1,0', '-1,' or '-1' are considered valid
4
+ * add test for '-value' and '+value'
5
+ * more test values and easier usage in tests
6
+
7
+ == 1.3.0 2009-09-06
8
+
9
+ * fix: helper amount_field_tag no works as expected (accepting name and value instead of object and method)
10
+ * add helper amount_field for ActionView::Base and amount_field for ActionView::Helpers::FormBuilder
11
+ * use an instance variable internally for the original assigned value and remove class AssignedValue
12
+
13
+ == 1.2.0 2009-09-04
14
+
15
+ * fix: an invalid value is still invalid after multiple calls to valid?
16
+
17
+ == 1.1.0 2009-08-31
18
+
19
+ * Fix "undefined method `to_f' for [...]:Array" by supported attribute of type float
20
+ (even if it is not a good idea to use float for amount because of rounding errors)
21
+ * Default configuration uses I18n.t('number.amount_field.format') from the plugin file
22
+ amount_field/locale/(en|de).yml. This means the default configuration depends on I18n.locale
23
+ and is not necessarily the german format by default anymore.
24
+ * The delimiter, separator and precision are now optional, so "1.234,00", "1234,00" and "1234" are
25
+ all valid at the same time.
26
+
27
+ == 1.0.2 2009-08-07
28
+
29
+ * fix typo and update readme concerning installation
30
+
31
+ == 1.0.1 2009-08-07
32
+
33
+ * Bugfix: a given format option for one amount field does not manipulate the default configuration
34
+
35
+ == 1.0.0 2009-07-28
36
+
37
+ * Initial release
38
+
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 [Thomas Baustert]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,20 @@
1
+ History.txt
2
+ MIT-LICENSE
3
+ Manifest
4
+ README.rdoc
5
+ Rakefile
6
+ init.rb
7
+ install.rb
8
+ lib/amount_field.rb
9
+ lib/amount_field/configuration.rb
10
+ lib/amount_field/form_helper.rb
11
+ lib/amount_field/form_tag_helper.rb
12
+ lib/amount_field/validations.rb
13
+ locale/de.yml
14
+ locale/en.yml
15
+ test/form_helper_test.rb
16
+ test/form_tag_helper_test.rb
17
+ test/models/test_product.rb
18
+ test/test_helper.rb
19
+ test/validations_test.rb
20
+ uninstall.rb
@@ -0,0 +1,181 @@
1
+ = AmountField
2
+
3
+ Rails gem/plugin that accepts (amount) values in german or us format like 1.234,56 or 1,234.56".
4
+
5
+ Only tested for Rails 2.3. It may works with older versions but I haven't tested it.
6
+ Drop me a line if you encounter problems.
7
+
8
+ == Installation
9
+
10
+ As Gem:
11
+
12
+ $ gem sources -a http://gems.github.com (you only have to do this once)
13
+ $ sudo gem install thomasbaustert-amount_field
14
+
15
+ As plugin:
16
+
17
+ $ script/plugin install git://github.com/thomasbaustert/amount_field.git
18
+
19
+ == Example
20
+
21
+ First: Use the helper <tt>amount_field</tt> instead of the <tt>text_field</tt> helper:
22
+
23
+ <% form_for(@product) do |f| %>
24
+ <%= f.amount_field :price %>
25
+ ...
26
+ <% end %>
27
+
28
+ <% form_for(@product) do |f| %>
29
+ <%= amount_field :product, :price %>
30
+ ...
31
+ <% end %>
32
+
33
+ The helper <tt>amount_field_tag</tt> is provided too, but you have to handle the validation on
34
+ your own:
35
+
36
+ <% form_tag(:action => "create", {}) do -%>
37
+ <%= amount_field_tag :price, 1234.56 %>
38
+ ...
39
+
40
+ Second: Use the validation macro <tt>validates_amount_format_of</tt> in your model:
41
+
42
+ class Product < ActiveRecord::Base
43
+ validates_amount_format_of :price
44
+ validates_numericality_of :price
45
+ validates_presence_of :price
46
+ ...
47
+ end
48
+
49
+ Note! Make sure you always call <tt>validates_amount_format_of</tt> *before* every
50
+ other validation macro for the same attribute (e.g. before <tt>validates_numericality_of</tt>
51
+ and <tt>validates_presence_of</tt> for <tt>price</tt>).
52
+
53
+ == Configuration
54
+
55
+ The following configuration is supported:
56
+
57
+ === Format Configuration
58
+
59
+ Definition:
60
+
61
+ Delimiter = thousand separator (e.g. '.' in 1.234.567)
62
+ Separator = separator of value and decimal places (e.g. ',' in 12,56)
63
+ Precision = number of decimal places
64
+
65
+ The default format configuration is defined via Rails I18n and accessable through the key
66
+ <tt>number.amount_field.format</tt> from the file <tt>amount_field/locale/(en|de).yml</tt>.
67
+
68
+ Example:
69
+
70
+ I18n.locale = :de
71
+ I18n.t('number.amount_field.format') # => { :precision => 2, :delimiter => '.', :separator => ',' }
72
+
73
+ Currently only the locale <tt>de</tt> and<tt>en</tt> are supported.
74
+
75
+ If you want to define the default configuration independent from I18n, you can set it as follows:
76
+
77
+ AmountField::ActiveRecord::Validations.configuration =
78
+ { :precision => 1, :delimiter => ',', :separator => '.' }
79
+
80
+ An explicitly defined format will overwrite the default configuration for that attribute:
81
+
82
+ validates_amount_format_of :price, :separator => '.', :delimiter => ',', :precision => 1
83
+ # VALID: "1,234.5" (1234.5)
84
+
85
+ Standard Rails options like <tt>:allow_blank</tt>, or <tt>:allow_nil</tt> are supported:
86
+
87
+ validates_amount_format_of :price, :allow_blank => true
88
+
89
+ === CSS class and prefix
90
+
91
+ By default the input field contains the CSS class <tt>amount_field</tt> so you can define
92
+ a CSS layout for every amount field like:
93
+
94
+ input.amount_field {
95
+ text-align:right;
96
+ }
97
+
98
+ The method prefix and the CSS class can be changed as follows:
99
+
100
+ AmountField::Configuration.prefix = "my_prefix"
101
+ AmountField::Configuration.css_class = "my_class"
102
+
103
+ That will create the html:
104
+
105
+ <input name="product[my_prefix_price]" class=" my_class"...
106
+
107
+ and the appropriate method <tt>my_prefix_price=(value)</tt>.
108
+
109
+ == Input
110
+
111
+ By default delimiter, separator and precision are optional, so "1.234,00", "1234,00" and "1234"
112
+ are all valid for the german locale (de) at the same time.
113
+
114
+ In all other cases the validation will fail and add an error message to the original
115
+ attribute (e.g. <tt>price</tt>). (See Error Messages)
116
+
117
+ == Output
118
+
119
+ The helper <tt>amount_field</tt> uses the Rails helper <tt>number_with_precision</tt> internally
120
+ and passes the plugin format configuration as an argument. A value like 1234.56 is therefore
121
+ displayed as "1.234,56" for the locale <tt>de</tt> and "1,234.56" for the locale <tt>en</tt>.
122
+
123
+ You can explicitly set the format configuration with the option <tt>format</tt>:
124
+
125
+ amount_field(:price, :format => { :separator => '', ... })
126
+
127
+ And it is possible to pass the value explicitly:
128
+
129
+ amount_field(:price, :value => ...)
130
+
131
+ == Error Messages
132
+
133
+ By default the german and english messages are taken from the file
134
+ <tt>amount_field/locale/(en|de).yml</tt> through the key
135
+ <tt>activerecord.errors.messages.invalid_amount_format</tt>.
136
+
137
+ You can define your own by adding your Yaml file to the load path like:
138
+
139
+ # environment.rb
140
+ I18n.load_path << "#{RAILS_ROOT}/locale/en.yml"
141
+
142
+ # "#{RAILS_ROOT}/locale/en.yml"
143
+ de:
144
+ activerecord:
145
+ errors:
146
+ messages:
147
+ invalid_amount_format: "bla ... '{{value}}' blub ... ({{format_example}})"
148
+
149
+ The placeholder <tt>{{value}}</tt> is substituted with the given value (e.g. "1.x") and
150
+ <tt>{{format_example}}</tt> with a valid example of the currently accepted format (e.g. 'd.ddd,dd').
151
+
152
+ == How does it work?
153
+
154
+ Basically the helper <tt>amount_field</tt> defines a input field like so:
155
+
156
+ <input name="product[amount_field_price]" class=" amount_field"...
157
+
158
+ The validation macro <tt>validates_amount_format_of</tt> defines a special setter method
159
+ <tt>amount_field_price=(value)</tt> that accept the value. After successfully format
160
+ validation the original parameter is converted to a ruby value (e.g. "1.234,56" to 1234.56)
161
+ and assigned to the original attribute <tt>price</tt>. Following validation macros work on
162
+ the converted value. That's why it is currently important to call
163
+ <tt>validates_amount_format_of</tt> before every other macro.
164
+
165
+ == Running Tests
166
+
167
+ You need a database <tt>gem_amount_field_test</tt> to run all tests.
168
+ See test_helper.rb for details.
169
+
170
+ == Credits
171
+
172
+ * Michael Schiller (for feedback and ideas)
173
+
174
+ == Contact
175
+
176
+ For comments and question feel free to contact me: business@thomasbaustert.de
177
+
178
+ If you are using the plugin, consider recommending me at workingwithrails.com:
179
+ http://workingwithrails.com/person/6131-thomas-baustert
180
+
181
+ Copyright (c) 2009 [Thomas Baustert], released under the MIT license
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('amount_field', '1.4.0') do |p|
6
+ p.description = "Rails gem/plugin that accepts (amount) values in german or us format like 1.234,56 or 1,234.56"
7
+ p.url = "http://github.com/thomasbaustert/amount_field"
8
+ p.author = "Thomas Baustert"
9
+ p.email =" business@thomasbaustert.de"
10
+ p.ignore_pattern = ["tmp/*", "script/*"]
11
+ p.development_dependencies = []
12
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{amount_field}
5
+ s.version = "1.4.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Thomas Baustert"]
9
+ s.date = %q{2009-10-06}
10
+ s.description = %q{Rails gem/plugin that accepts (amount) values in german or us format like 1.234,56 or 1,234.56}
11
+ s.email = %q{ business@thomasbaustert.de}
12
+ s.extra_rdoc_files = ["README.rdoc", "lib/amount_field.rb", "lib/amount_field/configuration.rb", "lib/amount_field/form_helper.rb", "lib/amount_field/form_tag_helper.rb", "lib/amount_field/validations.rb"]
13
+ s.files = ["History.txt", "MIT-LICENSE", "Manifest", "README.rdoc", "Rakefile", "init.rb", "install.rb", "lib/amount_field.rb", "lib/amount_field/configuration.rb", "lib/amount_field/form_helper.rb", "lib/amount_field/form_tag_helper.rb", "lib/amount_field/validations.rb", "locale/de.yml", "locale/en.yml", "test/form_helper_test.rb", "test/form_tag_helper_test.rb", "test/models/test_product.rb", "test/test_helper.rb", "test/validations_test.rb", "uninstall.rb", "amount_field.gemspec"]
14
+ s.homepage = %q{http://github.com/thomasbaustert/amount_field}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Amount_field", "--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{amount_field}
18
+ s.rubygems_version = %q{1.3.5}
19
+ s.summary = %q{Rails gem/plugin that accepts (amount) values in german or us format like 1.234,56 or 1,234.56}
20
+ s.test_files = ["test/form_helper_test.rb", "test/form_tag_helper_test.rb", "test/models/test_product.rb", "test/test_helper.rb", "test/validations_test.rb"]
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ else
28
+ end
29
+ else
30
+ end
31
+ end
data/init.rb ADDED
@@ -0,0 +1,4 @@
1
+ # Include hook code here
2
+
3
+ require 'amount_field'
4
+
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,22 @@
1
+ # AmountField
2
+
3
+ require 'amount_field/validations'
4
+ require 'amount_field/form_helper'
5
+ require 'amount_field/form_tag_helper'
6
+
7
+ ActiveRecord::Base.class_eval do
8
+ include AmountField::ActiveRecord::Validations
9
+ end
10
+
11
+ ActionView::Helpers::FormBuilder.class_eval do
12
+ include AmountField::Helpers::FormBuilder
13
+ end
14
+
15
+ ActionView::Base.class_eval do
16
+ include AmountField::Helpers::FormHelper
17
+ include AmountField::Helpers::FormTagHelper
18
+ end
19
+
20
+ I18n.load_path << "#{File.dirname(__FILE__)}/../locale/en.yml"
21
+ I18n.load_path << "#{File.dirname(__FILE__)}/../locale/de.yml"
22
+
@@ -0,0 +1,20 @@
1
+ module AmountField
2
+ class Configuration
3
+
4
+ ##
5
+ # Defines the prefix for the special setter method name:
6
+ # def #{prefix}_xxx=(value) ...
7
+ # end
8
+ #
9
+ @@prefix = 'amount_field'
10
+ mattr_accessor :prefix
11
+
12
+ ##
13
+ # Defines the CSS class name for the <tt>amount_field</tt> helper.
14
+ # <input ...class="... #{css_class}" .../>
15
+ #
16
+ @@css_class = 'amount_field'
17
+ mattr_accessor :css_class
18
+
19
+ end
20
+ end
@@ -0,0 +1,62 @@
1
+ module AmountField #:nodoc:
2
+ module Helpers #:nodoc:
3
+
4
+ module FormHelper #:nodoc:
5
+
6
+ include ActionView::Helpers::NumberHelper
7
+
8
+ def amount_field(object_name, method, options = {})
9
+ format_options = I18n.t(:'number.amount_field.format', :raise => true) rescue {}
10
+ format_options = format_options.merge(AmountField::ActiveRecord::Validations.configuration)
11
+ format_options.merge!(options.delete(:format) || {})
12
+
13
+ object = options.delete(:object) || instance_variable_get("@#{object_name}")
14
+
15
+ # if no explicit value is given, we set a formatted one. In case of an error we take the
16
+ # original value inserted by the user.
17
+ unless object.errors.on(method)
18
+ options[:value] ||= number_with_precision(object.send(method), format_options)
19
+ else
20
+ options[:value] ||= object.send("#{method}_before_type_cast")
21
+ end
22
+ options[:name] = "#{object_name}[#{AmountField::Configuration.prefix}_#{method}]"
23
+ options[:class] = "#{options[:class]} #{AmountField::Configuration.css_class}"
24
+ options[:id] ||= "#{object_name}_#{method}"
25
+
26
+ text_field(object_name, method, options)
27
+ end
28
+
29
+ end
30
+
31
+ module FormBuilder #:nodoc:
32
+
33
+ include ActionView::Helpers::NumberHelper
34
+
35
+ def amount_field(method, options = {})
36
+ #todo try to remove redundant code by using: @template.amount_field(object, method, options)
37
+ format_options = I18n.t(:'number.amount_field.format', :raise => true) rescue {}
38
+ format_options = format_options.merge(AmountField::ActiveRecord::Validations.configuration)
39
+ format_options.merge!(options.delete(:format) || {})
40
+
41
+ if (explicit_object = options.delete(:object))
42
+ self.object = explicit_object
43
+ end
44
+
45
+ # if no explicit value is given, we set a formatted one. In case of an error we take the
46
+ # original value inserted by the user.
47
+ unless object.errors.on(method)
48
+ options[:value] ||= number_with_precision(object.send(method), format_options)
49
+ else
50
+ options[:value] ||= object.send("#{method}_before_type_cast")
51
+ end
52
+ options[:name] = "#{object_name}[#{AmountField::Configuration.prefix}_#{method}]"
53
+ options[:class] = "#{options[:class]} #{AmountField::Configuration.css_class}"
54
+
55
+ text_field(method, options)
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+ end
62
+
@@ -0,0 +1,22 @@
1
+ module AmountField #:nodoc:
2
+ module Helpers #:nodoc:
3
+ module FormTagHelper
4
+ include ActionView::Helpers::NumberHelper
5
+
6
+ def amount_field_tag(name, value = nil, options = {})
7
+ format_options = I18n.t(:'number.amount_field.format', :raise => true) rescue {}
8
+ format_options = format_options.merge(AmountField::ActiveRecord::Validations.configuration)
9
+ format_options.merge!(options.delete(:format) || {})
10
+
11
+ # if no explicit value is given, we set a formatted one. In case of an error we take the
12
+ # original value inserted by the user.
13
+ options[:value] ||= number_with_precision(value.to_s, format_options)
14
+ options[:name] = "#{AmountField::Configuration.prefix}_#{name}"
15
+ options[:class] = "#{options[:class]} #{AmountField::Configuration.css_class}"
16
+
17
+ text_field_tag(name, value, options)
18
+ end
19
+
20
+ end
21
+ end
22
+ end