amount_field_rails3 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ doc
6
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
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
@@ -0,0 +1,4 @@
1
+ # Include hook code here
2
+
3
+ require 'amount_field'
4
+
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -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
+