amount_field_rails3 3.0.0
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.
- data/.gitignore +6 -0
- data/Gemfile +3 -0
- data/History.txt +58 -0
- data/MIT-LICENSE +20 -0
- data/Manifest +21 -0
- data/README.rdoc +196 -0
- data/Rakefile +16 -0
- data/amount_field.gemspec +25 -0
- data/init.rb +4 -0
- data/install.rb +1 -0
- data/lib/amount_field.rb +23 -0
- data/lib/amount_field/configuration.rb +20 -0
- data/lib/amount_field/form_helper.rb +68 -0
- data/lib/amount_field/form_tag_helper.rb +22 -0
- data/lib/amount_field/validations.rb +129 -0
- data/lib/amount_field/version.rb +3 -0
- data/locale/de.yml +10 -0
- data/locale/en.yml +11 -0
- data/test/form_helper_test.rb +264 -0
- data/test/form_tag_helper_test.rb +47 -0
- data/test/models/test_product.rb +7 -0
- data/test/test_helper.rb +63 -0
- data/test/validations_test.rb +389 -0
- data/uninstall.rb +1 -0
- metadata +104 -0
data/Gemfile
ADDED
data/History.txt
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
== 3.0.0 2011-03-29
|
2
|
+
|
3
|
+
* Migrate to Rails3
|
4
|
+
|
5
|
+
== 1.4.2 2010-05-11
|
6
|
+
|
7
|
+
* Don't set default dom Id for FormBuilder amount_field, use Rails default or use given one.
|
8
|
+
|
9
|
+
== 1.4.1 2010-04-23
|
10
|
+
|
11
|
+
* Method amount_field considers given option "name" and "id":
|
12
|
+
<% form_for(@manager) do |f| %>
|
13
|
+
<%= f.amount_field :salary, :name => :salary, :id => "salary_id" %>
|
14
|
+
...
|
15
|
+
=>
|
16
|
+
<input name="salary" id="salary_id" ... /> instead of
|
17
|
+
<input name="manager[amount_field_value]" id="manager_salary"... />
|
18
|
+
* fix: display invalid value in current format (e.g. in german format: "-0,1" or "12,34"
|
19
|
+
and not "-0.1" and "12.34").
|
20
|
+
|
21
|
+
== 1.4.0 2009-10-06
|
22
|
+
|
23
|
+
* fix: negative values like '-1,00', '-1,0', '-1,' or '-1' are considered valid
|
24
|
+
* add test for '-value' and '+value'
|
25
|
+
* more test values and easier usage in tests
|
26
|
+
|
27
|
+
== 1.3.0 2009-09-06
|
28
|
+
|
29
|
+
* fix: helper amount_field_tag no works as expected (accepting name and value instead of object and method)
|
30
|
+
* add helper amount_field for ActionView::Base and amount_field for ActionView::Helpers::FormBuilder
|
31
|
+
* use an instance variable internally for the original assigned value and remove class AssignedValue
|
32
|
+
|
33
|
+
== 1.2.0 2009-09-04
|
34
|
+
|
35
|
+
* fix: an invalid value is still invalid after multiple calls to valid?
|
36
|
+
|
37
|
+
== 1.1.0 2009-08-31
|
38
|
+
|
39
|
+
* Fix "undefined method `to_f' for [...]:Array" by supported attribute of type float
|
40
|
+
(even if it is not a good idea to use float for amount because of rounding errors)
|
41
|
+
* Default configuration uses I18n.t('number.amount_field.format') from the plugin file
|
42
|
+
amount_field/locale/(en|de).yml. This means the default configuration depends on I18n.locale
|
43
|
+
and is not necessarily the german format by default anymore.
|
44
|
+
* The delimiter, separator and precision are now optional, so "1.234,00", "1234,00" and "1234" are
|
45
|
+
all valid at the same time.
|
46
|
+
|
47
|
+
== 1.0.2 2009-08-07
|
48
|
+
|
49
|
+
* fix typo and update readme concerning installation
|
50
|
+
|
51
|
+
== 1.0.1 2009-08-07
|
52
|
+
|
53
|
+
* Bugfix: a given format option for one amount field does not manipulate the default configuration
|
54
|
+
|
55
|
+
== 1.0.0 2009-07-28
|
56
|
+
|
57
|
+
* Initial release
|
58
|
+
|
data/MIT-LICENSE
ADDED
@@ -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.
|
data/Manifest
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
History.txt
|
2
|
+
MIT-LICENSE
|
3
|
+
Manifest
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
amount_field.gemspec
|
7
|
+
init.rb
|
8
|
+
install.rb
|
9
|
+
lib/amount_field.rb
|
10
|
+
lib/amount_field/configuration.rb
|
11
|
+
lib/amount_field/form_helper.rb
|
12
|
+
lib/amount_field/form_tag_helper.rb
|
13
|
+
lib/amount_field/validations.rb
|
14
|
+
locale/de.yml
|
15
|
+
locale/en.yml
|
16
|
+
test/form_helper_test.rb
|
17
|
+
test/form_tag_helper_test.rb
|
18
|
+
test/models/test_product.rb
|
19
|
+
test/test_helper.rb
|
20
|
+
test/validations_test.rb
|
21
|
+
uninstall.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,196 @@
|
|
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
|
+
== Installation Rails 3
|
6
|
+
|
7
|
+
Via Bundler:
|
8
|
+
|
9
|
+
# path/to/railsapp/Gemfile
|
10
|
+
gem 'amount_field_rails3', :require => 'amount_field'
|
11
|
+
|
12
|
+
$ bundle install
|
13
|
+
|
14
|
+
As Gem:
|
15
|
+
|
16
|
+
$ gem sources -a http://gemcutter.org/ (you only have to do this once)
|
17
|
+
$ sudo gem install amount_field_rails3
|
18
|
+
|
19
|
+
As plugin:
|
20
|
+
|
21
|
+
$ rails plugin install git://github.com/thomasbaustert/amount_field.git
|
22
|
+
|
23
|
+
== Installation Rails 2.x
|
24
|
+
|
25
|
+
As Gem:
|
26
|
+
|
27
|
+
$ gem sources -a http://gemcutter.org/ (you only have to do this once)
|
28
|
+
$ sudo gem install amount_field
|
29
|
+
|
30
|
+
As plugin:
|
31
|
+
|
32
|
+
$ script/plugin install git://github.com/thomasbaustert/amount_field.git, :branch => 'rails23'
|
33
|
+
|
34
|
+
== Example
|
35
|
+
|
36
|
+
First: Use the helper <tt>amount_field</tt> instead of the <tt>text_field</tt> helper:
|
37
|
+
|
38
|
+
<%= form_for(@product) do |f| %>
|
39
|
+
<%= f.amount_field :price %>
|
40
|
+
...
|
41
|
+
<% end %>
|
42
|
+
|
43
|
+
<%= form_for(@product) do |f| %>
|
44
|
+
<%= amount_field :product, :price %>
|
45
|
+
...
|
46
|
+
<% end %>
|
47
|
+
|
48
|
+
The helper <tt>amount_field_tag</tt> is provided too, but you have to handle the validation on
|
49
|
+
your own:
|
50
|
+
|
51
|
+
<%= form_tag(:action => "create", {}) do -%>
|
52
|
+
<%= amount_field_tag :price, 1234.56 %>
|
53
|
+
...
|
54
|
+
|
55
|
+
Second: Use the validation macro <tt>validates_amount_format_of</tt> in your model:
|
56
|
+
|
57
|
+
class Product < ActiveRecord::Base
|
58
|
+
validates_amount_format_of :price
|
59
|
+
validates_numericality_of :price
|
60
|
+
validates_presence_of :price
|
61
|
+
...
|
62
|
+
end
|
63
|
+
|
64
|
+
Note! Make sure you always call <tt>validates_amount_format_of</tt> *before* every
|
65
|
+
other validation macro for the same attribute (e.g. before <tt>validates_numericality_of</tt>
|
66
|
+
and <tt>validates_presence_of</tt> for <tt>price</tt>).
|
67
|
+
|
68
|
+
== Configuration
|
69
|
+
|
70
|
+
The following configuration is supported:
|
71
|
+
|
72
|
+
=== Format Configuration
|
73
|
+
|
74
|
+
Definition:
|
75
|
+
|
76
|
+
Delimiter = thousand separator (e.g. '.' in 1.234.567)
|
77
|
+
Separator = separator of value and decimal places (e.g. ',' in 12,56)
|
78
|
+
Precision = number of decimal places
|
79
|
+
|
80
|
+
The default format configuration is defined via Rails I18n and accessable through the key
|
81
|
+
<tt>number.amount_field.format</tt> from the file <tt>amount_field/locale/(en|de).yml</tt>.
|
82
|
+
|
83
|
+
Example:
|
84
|
+
|
85
|
+
I18n.locale = :de
|
86
|
+
I18n.t('number.amount_field.format') # => { :precision => 2, :delimiter => '.', :separator => ',' }
|
87
|
+
|
88
|
+
Currently only the locale <tt>de</tt> and<tt>en</tt> are supported.
|
89
|
+
|
90
|
+
If you want to define the default configuration independent from I18n, you can set it as follows:
|
91
|
+
|
92
|
+
AmountField::ActiveRecord::Validations.configuration =
|
93
|
+
{ :precision => 1, :delimiter => ',', :separator => '.' }
|
94
|
+
|
95
|
+
An explicitly defined format will overwrite the default configuration for that attribute:
|
96
|
+
|
97
|
+
validates_amount_format_of :price, :separator => '.', :delimiter => ',', :precision => 1
|
98
|
+
# VALID: "1,234.5" (1234.5)
|
99
|
+
|
100
|
+
Standard Rails options like <tt>:allow_blank</tt>, or <tt>:allow_nil</tt> are supported:
|
101
|
+
|
102
|
+
validates_amount_format_of :price, :allow_blank => true
|
103
|
+
|
104
|
+
=== CSS class and prefix
|
105
|
+
|
106
|
+
By default the input field contains the CSS class <tt>amount_field</tt> so you can define
|
107
|
+
a CSS layout for every amount field like:
|
108
|
+
|
109
|
+
input.amount_field {
|
110
|
+
text-align:right;
|
111
|
+
}
|
112
|
+
|
113
|
+
The method prefix and the CSS class can be changed as follows:
|
114
|
+
|
115
|
+
AmountField::Configuration.prefix = "my_prefix"
|
116
|
+
AmountField::Configuration.css_class = "my_class"
|
117
|
+
|
118
|
+
That will create the html:
|
119
|
+
|
120
|
+
<input name="product[my_prefix_price]" class=" my_class"...
|
121
|
+
|
122
|
+
and the appropriate method <tt>my_prefix_price=(value)</tt>.
|
123
|
+
|
124
|
+
== Input
|
125
|
+
|
126
|
+
By default delimiter, separator and precision are optional, so "1.234,00", "1234,00" and "1234"
|
127
|
+
are all valid for the german locale (de) at the same time.
|
128
|
+
|
129
|
+
In all other cases the validation will fail and add an error message to the original
|
130
|
+
attribute (e.g. <tt>price</tt>). (See Error Messages)
|
131
|
+
|
132
|
+
== Output
|
133
|
+
|
134
|
+
The helper <tt>amount_field</tt> uses the Rails helper <tt>number_with_precision</tt> internally
|
135
|
+
and passes the plugin format configuration as an argument. A value like 1234.56 is therefore
|
136
|
+
displayed as "1.234,56" for the locale <tt>de</tt> and "1,234.56" for the locale <tt>en</tt>.
|
137
|
+
|
138
|
+
You can explicitly set the format configuration with the option <tt>format</tt>:
|
139
|
+
|
140
|
+
amount_field(:price, :format => { :separator => '', ... })
|
141
|
+
|
142
|
+
And it is possible to pass the value explicitly:
|
143
|
+
|
144
|
+
amount_field(:price, :value => ...)
|
145
|
+
|
146
|
+
== Error Messages
|
147
|
+
|
148
|
+
By default the german and english messages are taken from the file
|
149
|
+
<tt>amount_field/locale/(en|de).yml</tt> through the key
|
150
|
+
<tt>activerecord.errors.messages.invalid_amount_format</tt>.
|
151
|
+
|
152
|
+
You can define your own by adding your Yaml file to the load path like:
|
153
|
+
|
154
|
+
# environment.rb
|
155
|
+
I18n.load_path << "#{RAILS_ROOT}/locale/en.yml"
|
156
|
+
|
157
|
+
# "#{RAILS_ROOT}/locale/en.yml"
|
158
|
+
de:
|
159
|
+
errors:
|
160
|
+
messages:
|
161
|
+
invalid_amount_format: "'%{value}' ist ein ungültiges Format (%{format_example})"
|
162
|
+
|
163
|
+
The placeholder <tt>%{value}</tt> is substituted with the given value (e.g. "1.x") and
|
164
|
+
<tt>%{format_example}</tt> with a valid example of the currently accepted format (e.g. 'd.ddd,dd').
|
165
|
+
|
166
|
+
== How does it work?
|
167
|
+
|
168
|
+
Basically the helper <tt>amount_field</tt> defines a input field like so:
|
169
|
+
|
170
|
+
<input name="product[amount_field_price]" class=" amount_field"...
|
171
|
+
|
172
|
+
The validation macro <tt>validates_amount_format_of</tt> defines a special setter method
|
173
|
+
<tt>amount_field_price=(value)</tt> that accept the value. After successfully format
|
174
|
+
validation the original parameter is converted to a ruby value (e.g. "1.234,56" to 1234.56)
|
175
|
+
and assigned to the original attribute <tt>price</tt>. Following validation macros work on
|
176
|
+
the converted value. That's why it is currently important to call
|
177
|
+
<tt>validates_amount_format_of</tt> before every other macro.
|
178
|
+
|
179
|
+
== Running Tests
|
180
|
+
|
181
|
+
You need a database <tt>gem_amount_field_test</tt> to run all tests.
|
182
|
+
See test_helper.rb for details.
|
183
|
+
|
184
|
+
== Credits
|
185
|
+
|
186
|
+
* Michael Schiller (for feedback and ideas)
|
187
|
+
* Clements Teichmann (consider option 'name' and 'id')
|
188
|
+
|
189
|
+
== Contact
|
190
|
+
|
191
|
+
For comments and question feel free to contact me: business@thomasbaustert.de
|
192
|
+
|
193
|
+
If you are using the plugin, consider recommending me at workingwithrails.com:
|
194
|
+
http://workingwithrails.com/person/6131-thomas-baustert
|
195
|
+
|
196
|
+
Copyright (c) 2009 [Thomas Baustert], released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
|
8
|
+
desc 'Default: run tests'
|
9
|
+
task :default => :test
|
10
|
+
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs << 'lib'
|
13
|
+
t.libs << 'test'
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = true
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "amount_field/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "amount_field_rails3"
|
7
|
+
s.version = AmountField::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Thomas Baustert"]
|
10
|
+
s.email = ["business@thomasbaustert.de"]
|
11
|
+
s.homepage = "http://github.com/thomasbaustert/amount_field"
|
12
|
+
s.summary = %q{Rails gem/plugin that accepts (amount) values in german or us format like 1.234,56 or 1,234.56}
|
13
|
+
s.description = %q{Rails gem/plugin that accepts (amount) values in german or us format like 1.234,56 or 1,234.56}
|
14
|
+
|
15
|
+
s.rubyforge_project = "amount_field_rails3"
|
16
|
+
|
17
|
+
s.add_development_dependency "mysql2"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
end
|
24
|
+
|
25
|
+
|
data/init.rb
ADDED
data/install.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Install hook code here
|
data/lib/amount_field.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# AmountField
|
2
|
+
|
3
|
+
require 'amount_field/configuration'
|
4
|
+
require 'amount_field/validations'
|
5
|
+
require 'amount_field/form_helper'
|
6
|
+
require 'amount_field/form_tag_helper'
|
7
|
+
|
8
|
+
ActiveRecord::Base.class_eval do
|
9
|
+
include AmountField::ActiveRecord::Validations
|
10
|
+
end
|
11
|
+
|
12
|
+
ActionView::Helpers::FormBuilder.class_eval do
|
13
|
+
include AmountField::Helpers::FormBuilder
|
14
|
+
end
|
15
|
+
|
16
|
+
ActionView::Base.class_eval do
|
17
|
+
include AmountField::Helpers::FormHelper
|
18
|
+
include AmountField::Helpers::FormTagHelper
|
19
|
+
end
|
20
|
+
|
21
|
+
I18n.load_path << "#{File.dirname(__FILE__)}/../locale/en.yml"
|
22
|
+
I18n.load_path << "#{File.dirname(__FILE__)}/../locale/de.yml"
|
23
|
+
|
@@ -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,68 @@
|
|
1
|
+
module AmountField #:nodoc:
|
2
|
+
module Helpers #:nodoc:
|
3
|
+
|
4
|
+
#TODO/2010-04-23/tb remove redundant code
|
5
|
+
# using @template.amount_field(object, method, options) !?
|
6
|
+
|
7
|
+
module FormHelper
|
8
|
+
|
9
|
+
include ActionView::Helpers::NumberHelper
|
10
|
+
|
11
|
+
def amount_field(object_name, method, options = {})
|
12
|
+
format_options = I18n.t(:'number.amount_field.format', :raise => true) rescue {}
|
13
|
+
format_options = format_options.merge(AmountField::ActiveRecord::Validations.configuration)
|
14
|
+
format_options.merge!(options.delete(:format) || {})
|
15
|
+
|
16
|
+
object = options.delete(:object) || instance_variable_get("@#{object_name}")
|
17
|
+
|
18
|
+
# if no explicit value is given, we set a formatted one. In case of an error we take the
|
19
|
+
# original value inserted by the user.
|
20
|
+
if object.errors[method].blank?
|
21
|
+
options[:value] ||= number_with_precision(object.send(method), format_options)
|
22
|
+
else
|
23
|
+
options[:value] ||= object.send("#{AmountField::Configuration.prefix}_#{method}") || object.send("#{method}_before_type_cast")
|
24
|
+
end
|
25
|
+
|
26
|
+
options[:name] ||= "#{object_name}[#{AmountField::Configuration.prefix}_#{method}]"
|
27
|
+
options[:class] = "#{options[:class]} #{AmountField::Configuration.css_class}"
|
28
|
+
options[:id] ||= "#{object_name}_#{method}"
|
29
|
+
|
30
|
+
text_field(object_name, method, options)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
module FormBuilder
|
36
|
+
|
37
|
+
include ActionView::Helpers::NumberHelper
|
38
|
+
|
39
|
+
def amount_field(method, options = {})
|
40
|
+
format_options = I18n.t(:'number.amount_field.format', :raise => true) rescue {}
|
41
|
+
format_options = format_options.merge(AmountField::ActiveRecord::Validations.configuration)
|
42
|
+
format_options.merge!(options.delete(:format) || {})
|
43
|
+
|
44
|
+
if (explicit_object = options.delete(:object))
|
45
|
+
self.object = explicit_object
|
46
|
+
end
|
47
|
+
|
48
|
+
# if no explicit value is given, we set a formatted one. In case of an error we take the
|
49
|
+
# original value inserted by the user.
|
50
|
+
if object.errors[method].blank?
|
51
|
+
options[:value] ||= number_with_precision(object.send(method), format_options)
|
52
|
+
else
|
53
|
+
options[:value] ||= object.send("#{AmountField::Configuration.prefix}_#{method}") || object.send("#{method}_before_type_cast")
|
54
|
+
end
|
55
|
+
|
56
|
+
# Note: we don't set options[:id] here, because caller or Rails knows best what to do.
|
57
|
+
# We accidentally set it to "foo[bar]_name" instead of "foo_bar_name".
|
58
|
+
options[:name] ||= "#{object_name}[#{AmountField::Configuration.prefix}_#{method}]"
|
59
|
+
options[:class] = "#{options[:class]} #{AmountField::Configuration.css_class}"
|
60
|
+
|
61
|
+
text_field(method, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|