i18n_alchemy 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +9 -0
- data/MIT-LICENSE +20 -0
- data/README.md +118 -0
- data/lib/i18n_alchemy/association_parser.rb +49 -0
- data/lib/i18n_alchemy/attribute.rb +23 -0
- data/lib/i18n_alchemy/date_parser.rb +43 -0
- data/lib/i18n_alchemy/numeric_parser.rb +57 -0
- data/lib/i18n_alchemy/proxy.rb +136 -0
- data/lib/i18n_alchemy/time_parser.rb +22 -0
- data/lib/i18n_alchemy/version.rb +5 -0
- data/lib/i18n_alchemy.rb +17 -0
- data/test/action_view_test.rb +46 -0
- data/test/db/test_schema.rb +30 -0
- data/test/i18n_alchemy/date_parser_test.rb +40 -0
- data/test/i18n_alchemy/numeric_parser_test.rb +73 -0
- data/test/i18n_alchemy/proxy_test.rb +302 -0
- data/test/i18n_alchemy/time_parser_test.rb +67 -0
- data/test/locale/en.yml +15 -0
- data/test/locale/pt.yml +15 -0
- data/test/models/account.rb +5 -0
- data/test/models/product.rb +11 -0
- data/test/models/supplier.rb +9 -0
- data/test/test_helper.rb +26 -0
- metadata +152 -0
data/CHANGELOG.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
## master
|
2
|
+
|
3
|
+
* Basic localization for numeric, date and time attributes
|
4
|
+
* Accept hash of attributes on localized call
|
5
|
+
* Localize attributes=, assign_attributes, update_attribute, and update_attributes ([@tomas-stefano](https://github.com/tomas-stefano))
|
6
|
+
* Localize nested attributes ([@tomas-stefano](https://github.com/tomas-stefano))
|
7
|
+
* JRuby compatibility ([@sobrinho](https://github.com/sobrinho))
|
8
|
+
* Format numeric values based on the current I18n number precision, delimiter and thousand separator
|
9
|
+
* Support for Rails 3.0, 3.1 and 3.2
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Carlos Antonio da Silva (carlosantoniodasilva@gmail.com)
|
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/README.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
## I18nAlchemy
|
2
|
+
|
3
|
+
I18n date/number parsing/localization
|
4
|
+
|
5
|
+
I18nAlchemy aims to handle date, time and number parsing, based on current I18n locale format. The main idea is to have ORMs, such as ActiveRecord for now, to automatically accept dates/numbers given in the current locale format, and return these values localized as well.
|
6
|
+
|
7
|
+
### Why
|
8
|
+
|
9
|
+
Almost all projects I've been working so far required some sort of input using dates and numbers, and it has always been a pain due to lack of this support in ActiveRecord itself. As I do most of my projects using different date/number formats than the English defaults (I live in Brazil), we've been adopting different ways to handle that in each application.
|
10
|
+
|
11
|
+
I've already used the delocalize gem in some of these projects, and validates_timeliness parser in others, and both work pretty well actually. But I think it might work a bit different than delocalize, and mainly, I wanted to learn more about I18n and ActiveRecord internals.
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
I18nAlchemy is pretty straigthforward to use, you just need to include it in your ActiveRecord model. Lets say we are working with a Product model:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
class Product < ActiveRecord::Base
|
19
|
+
include I18n::Alchemy
|
20
|
+
end
|
21
|
+
```
|
22
|
+
|
23
|
+
By mixing the module into your model, you get the *localized* method:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
@product = Product.first
|
27
|
+
@localized = @product.localized
|
28
|
+
```
|
29
|
+
|
30
|
+
Here are some examples on how to use it with numeric values:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
@localized.price = "1.99"
|
34
|
+
|
35
|
+
@product.price # => 1.99
|
36
|
+
@localized.price # => "1.99"
|
37
|
+
|
38
|
+
I18n.with_locale :pt do
|
39
|
+
@localized.price = "1,88"
|
40
|
+
|
41
|
+
@product.price # => 1.88
|
42
|
+
@localized.price # => "1,88"
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
Please notice that the localized proxy also formats your numeric values based on the current precision in your I18n locale file:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
@product.price = 1.3
|
50
|
+
@localized.price # => "1.30", considering a precision of 2
|
51
|
+
```
|
52
|
+
|
53
|
+
And with thousand separators as well:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
@product.price = 1840.32
|
57
|
+
@localized.price # => "1,840.32", considering separator = "," and delimiter = "."
|
58
|
+
```
|
59
|
+
|
60
|
+
Some examples with date / time objects:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
@localized.released_at = "12/31/2011"
|
64
|
+
|
65
|
+
@product.released_at # => Date.new(2011, 12, 31)
|
66
|
+
@localized.released_at # => "12/31/2011"
|
67
|
+
|
68
|
+
I18n.with_locale :pt do
|
69
|
+
@localized.released_at = "31/12/2011"
|
70
|
+
|
71
|
+
@product.released_at # => Date.new(2011, 12, 31)
|
72
|
+
@localized.released_at # => "31/12/2011"
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
The localized method quacks like ActiveRecord: you can give a hash of attributes and extra options if you want, and it will delegate everything to the object, parsing the attributes before:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
# This will parse the attributes in the given hash.
|
80
|
+
I18n.with_locale :pt do
|
81
|
+
@localized = @product.localized(:price => "1,88")
|
82
|
+
|
83
|
+
@product.price # => 1.88
|
84
|
+
@localized.price # => "1,88"
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
## I18n configuration
|
89
|
+
|
90
|
+
Right now the lib uses the same configuration for numeric, date and time values from Rails:
|
91
|
+
|
92
|
+
```yaml
|
93
|
+
en:
|
94
|
+
|
95
|
+
date:
|
96
|
+
formats:
|
97
|
+
default: "%m/%d/%Y"
|
98
|
+
|
99
|
+
time:
|
100
|
+
formats:
|
101
|
+
default: "%m/%d/%Y %H:%M:%S"
|
102
|
+
|
103
|
+
number:
|
104
|
+
format:
|
105
|
+
separator: '.'
|
106
|
+
delimiter: ','
|
107
|
+
precision: 2
|
108
|
+
```
|
109
|
+
|
110
|
+
Please notice the default date and time format is considered for input values for now, and it will only accept valid values matching these formats. We plan to add specific formats and to parse a list of possible input formats for I18nAlchemy, to make it more flexible, please refer to TODO file for more info.
|
111
|
+
|
112
|
+
## Contact
|
113
|
+
|
114
|
+
Carlos Antonio da Silva (http://github.com/carlosantoniodasilva)
|
115
|
+
|
116
|
+
## License
|
117
|
+
|
118
|
+
MIT License.
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module I18n
|
2
|
+
module Alchemy
|
3
|
+
class AssociationParser
|
4
|
+
attr_reader :target_class, :association_name
|
5
|
+
|
6
|
+
def initialize(target_class, association_name)
|
7
|
+
@target_class = target_class
|
8
|
+
@association_name = association_name
|
9
|
+
@association = @target_class.reflect_on_association(@association_name)
|
10
|
+
@proxy = @association.klass.new.localized
|
11
|
+
end
|
12
|
+
|
13
|
+
# Parse nested attributes for one-to-one and collection association
|
14
|
+
#
|
15
|
+
# ==== Examples
|
16
|
+
#
|
17
|
+
# parse(:avatar_attributes => {:icon => 'sad_panda'})
|
18
|
+
# parse(:posts_attributes => [{:title => 'Foo!'}, {:title => 'Bar!'}])
|
19
|
+
# parse(:posts_attributes => { 0 => {:title => 'Foo!'}, 1 => {:title => 'Bar!'})
|
20
|
+
# parse(:posts_attributes => { "81u21udjsndja" => {:title => 'Foo!'}, "akmsams" => {:title => 'Baz!'}})
|
21
|
+
#
|
22
|
+
def parse(attributes)
|
23
|
+
if @association.macro == :has_many
|
24
|
+
attributes = if attributes.is_a?(Hash)
|
25
|
+
attributes.values
|
26
|
+
else
|
27
|
+
attributes
|
28
|
+
end
|
29
|
+
attributes.collect { |value_attributes| @proxy.send(:parse_attributes, value_attributes) }
|
30
|
+
else
|
31
|
+
@proxy.send(:parse_attributes, attributes)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# ==== Examples
|
36
|
+
#
|
37
|
+
# class Member < ActiveRecord::Base
|
38
|
+
# has_one :avatar
|
39
|
+
# accepts_nested_attributes_for :avatar
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# AssociationParser.new(Member, :avatar).association_name_attributes # => "avatar_attributes"
|
43
|
+
#
|
44
|
+
def association_name_attributes
|
45
|
+
"#{association_name}_attributes"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module I18n
|
2
|
+
module Alchemy
|
3
|
+
class Attribute
|
4
|
+
def initialize(target, attribute, parser)
|
5
|
+
@target = target
|
6
|
+
@attribute = attribute
|
7
|
+
@parser = parser
|
8
|
+
end
|
9
|
+
|
10
|
+
def read
|
11
|
+
@parser.localize(@target.send(@attribute))
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(value)
|
15
|
+
@target.send(:"#{@attribute}=", parse(value))
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse(value)
|
19
|
+
@parser.parse(value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module I18n
|
2
|
+
module Alchemy
|
3
|
+
module DateParser
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def parse(value)
|
7
|
+
return value unless valid_for_parsing?(value)
|
8
|
+
|
9
|
+
if parsed_date = Date._strptime(value, i18n_format)
|
10
|
+
build_object(parsed_date).to_s
|
11
|
+
else
|
12
|
+
value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def localize(value)
|
17
|
+
valid_for_localization?(value) ? I18n.localize(value) : value
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def build_object(parsed_date)
|
23
|
+
Date.new(*parsed_date.values_at(:year, :mon, :mday))
|
24
|
+
end
|
25
|
+
|
26
|
+
def i18n_format
|
27
|
+
I18n.t(:default, :scope => [i18n_scope, :formats])
|
28
|
+
end
|
29
|
+
|
30
|
+
def i18n_scope
|
31
|
+
:date
|
32
|
+
end
|
33
|
+
|
34
|
+
def valid_for_localization?(value)
|
35
|
+
value.is_a?(Date)
|
36
|
+
end
|
37
|
+
|
38
|
+
def valid_for_parsing?(value)
|
39
|
+
!valid_for_localization?(value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module I18n
|
2
|
+
module Alchemy
|
3
|
+
module NumericParser
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def parse(value)
|
7
|
+
if valid_for_parsing?(value)
|
8
|
+
value.gsub(delimiter, '_').gsub(separator, '.')
|
9
|
+
else
|
10
|
+
value
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def localize(value)
|
15
|
+
if valid_for_localization?(value)
|
16
|
+
number_with_delimiter(format("%.#{precision}f", value))
|
17
|
+
else
|
18
|
+
value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def delimiter
|
25
|
+
translate :delimiter
|
26
|
+
end
|
27
|
+
|
28
|
+
def precision
|
29
|
+
translate :precision
|
30
|
+
end
|
31
|
+
|
32
|
+
def separator
|
33
|
+
translate :separator
|
34
|
+
end
|
35
|
+
|
36
|
+
def translate(key)
|
37
|
+
I18n.t(key, :scope => :"number.format")
|
38
|
+
end
|
39
|
+
|
40
|
+
def valid_for_localization?(value)
|
41
|
+
value.is_a?(Numeric) && !value.is_a?(Integer)
|
42
|
+
end
|
43
|
+
|
44
|
+
def valid_for_parsing?(value)
|
45
|
+
value.respond_to?(:gsub)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Logic extracted from Rails' number_with_delimiter helper.
|
49
|
+
NUMBER_WITH_DELIMITER = /(\d)(?=(\d\d\d)+(?!\d))/
|
50
|
+
def number_with_delimiter(number)
|
51
|
+
parts = number.split('.')
|
52
|
+
parts[0].gsub!(NUMBER_WITH_DELIMITER, "\\1#{delimiter}")
|
53
|
+
parts.join(separator)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module I18n
|
2
|
+
module Alchemy
|
3
|
+
# Depend on AS::BasicObject which has a "blank slate" - no methods.
|
4
|
+
class Proxy < ActiveSupport::BasicObject
|
5
|
+
# TODO: cannot assume _id is always a foreign key.
|
6
|
+
# Find a better way to find that and skip these columns.
|
7
|
+
def initialize(target, attributes=nil, *args)
|
8
|
+
@target = target
|
9
|
+
@localized_attributes = {}
|
10
|
+
|
11
|
+
@target.class.columns.each do |column|
|
12
|
+
next if column.primary || column.name.ends_with?("_id")
|
13
|
+
|
14
|
+
parser = detect_parser(column)
|
15
|
+
if parser
|
16
|
+
create_localized_attribute(column.name, parser)
|
17
|
+
define_localized_methods(column.name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
@localized_associations = @target.class.nested_attributes_options.map do |association_name, options|
|
22
|
+
::I18n::Alchemy::AssociationParser.new(@target.class, association_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
assign_attributes(attributes, *args) if attributes
|
26
|
+
end
|
27
|
+
|
28
|
+
def attributes=(attributes)
|
29
|
+
@target.attributes = parse_attributes(attributes)
|
30
|
+
end
|
31
|
+
|
32
|
+
# This method is added to the proxy even thought it does not exist in
|
33
|
+
# Rails 3.0 (only >= 3.1).
|
34
|
+
def assign_attributes(attributes, *args)
|
35
|
+
if @target.respond_to?(:assign_attributes)
|
36
|
+
@target.assign_attributes(parse_attributes(attributes), *args)
|
37
|
+
else
|
38
|
+
self.attributes = attributes
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def update_attributes(attributes, *args)
|
43
|
+
@target.update_attributes(parse_attributes(attributes), *args)
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_attributes!(attributes, *args)
|
47
|
+
@target.update_attributes!(parse_attributes(attributes), *args)
|
48
|
+
end
|
49
|
+
|
50
|
+
def update_attribute(attribute, value)
|
51
|
+
attributes = parse_attributes(attribute => value)
|
52
|
+
@target.update_attribute(attribute, attributes.values.first)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Override to_param to always return the +proxy.to_param+. This allow us
|
56
|
+
# to integrate with action view.
|
57
|
+
def to_param
|
58
|
+
@target.to_param
|
59
|
+
end
|
60
|
+
|
61
|
+
# Override to_model to always return the proxy, otherwise it returns the
|
62
|
+
# target object. This allows us to integrate with action view.
|
63
|
+
def to_model
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
# Allow calling localized methods with :send. This allows us to integrate
|
68
|
+
# with action view methods.
|
69
|
+
alias :send :__send__
|
70
|
+
|
71
|
+
# Allow calling localized methods with :try. If the method is not declared
|
72
|
+
# here, it'll be delegated to the target, losing localization capabilities.
|
73
|
+
def try(*a, &b)
|
74
|
+
__send__(*a, &b)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Delegate all method calls that are not translated to the target object.
|
78
|
+
# As the proxy does not have any other method, there is no need to
|
79
|
+
# override :respond_to, just delegate it to the target as well.
|
80
|
+
def method_missing(*args, &block)
|
81
|
+
@target.send(*args, &block)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def create_localized_attribute(column_name, parser)
|
87
|
+
@localized_attributes[column_name] =
|
88
|
+
::I18n::Alchemy::Attribute.new(@target, column_name, parser)
|
89
|
+
end
|
90
|
+
|
91
|
+
def define_localized_methods(column_name)
|
92
|
+
class << self; self; end.instance_eval do
|
93
|
+
define_method(column_name) do
|
94
|
+
@localized_attributes[column_name].read
|
95
|
+
end
|
96
|
+
|
97
|
+
# Before type cast must be localized to integrate with action view.
|
98
|
+
define_method("#{column_name}_before_type_cast") do
|
99
|
+
@localized_attributes[column_name].read
|
100
|
+
end
|
101
|
+
|
102
|
+
define_method("#{column_name}=") do |value|
|
103
|
+
@localized_attributes[column_name].write(value)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def detect_parser(column)
|
109
|
+
case
|
110
|
+
when column.number?
|
111
|
+
NumericParser
|
112
|
+
when column.type == :date
|
113
|
+
DateParser
|
114
|
+
when column.type == :datetime || column.type == :timestamp
|
115
|
+
TimeParser
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def parse_attributes(attributes)
|
120
|
+
attributes = attributes.stringify_keys
|
121
|
+
|
122
|
+
@localized_attributes.each do |column_name, attribute|
|
123
|
+
next unless attributes.key?(column_name)
|
124
|
+
attributes[column_name] = attribute.parse(attributes[column_name])
|
125
|
+
end
|
126
|
+
@localized_associations.each do |association_parser|
|
127
|
+
association_attributes = association_parser.association_name_attributes
|
128
|
+
next unless attributes.key?(association_attributes)
|
129
|
+
attributes[association_attributes] = association_parser.parse(attributes[association_attributes])
|
130
|
+
end
|
131
|
+
|
132
|
+
attributes
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module I18n
|
2
|
+
module Alchemy
|
3
|
+
module TimeParser
|
4
|
+
include DateParser
|
5
|
+
extend self
|
6
|
+
|
7
|
+
protected
|
8
|
+
|
9
|
+
def build_object(parsed_date)
|
10
|
+
Time.utc(*parsed_date.values_at(:year, :mon, :mday, :hour, :min, :sec))
|
11
|
+
end
|
12
|
+
|
13
|
+
def i18n_scope
|
14
|
+
:time
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid_for_localization?(value)
|
18
|
+
value.is_a?(Time) || value.is_a?(DateTime)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/i18n_alchemy.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "date"
|
2
|
+
require "active_record"
|
3
|
+
require "i18n"
|
4
|
+
require "i18n_alchemy/date_parser"
|
5
|
+
require "i18n_alchemy/time_parser"
|
6
|
+
require "i18n_alchemy/numeric_parser"
|
7
|
+
require "i18n_alchemy/attribute"
|
8
|
+
require "i18n_alchemy/association_parser"
|
9
|
+
require "i18n_alchemy/proxy"
|
10
|
+
|
11
|
+
module I18n
|
12
|
+
module Alchemy
|
13
|
+
def localized(attributes=nil, *args)
|
14
|
+
I18n::Alchemy::Proxy.new(self, attributes, *args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ActionViewTest < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@template = ActionView::Base.new
|
6
|
+
@product = Product.new(
|
7
|
+
:name => "Potato",
|
8
|
+
:quantity => 10,
|
9
|
+
:price => 1.99,
|
10
|
+
:released_at => Date.new(2011, 2, 28),
|
11
|
+
:last_sale_at => Time.mktime(2011, 2, 28, 13, 25, 30)
|
12
|
+
)
|
13
|
+
@localized = @product.localized
|
14
|
+
|
15
|
+
I18n.locale = :pt
|
16
|
+
end
|
17
|
+
|
18
|
+
def teardown
|
19
|
+
I18n.locale = :en
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_text_field_with_string_attribute
|
23
|
+
assert_equal '<input id="product_name" name="product[name]" size="30" type="text" value="Potato" />',
|
24
|
+
@template.text_field(:product, :name, :object => @localized)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_text_field_with_integer_attribute
|
28
|
+
assert_equal '<input id="product_quantity" name="product[quantity]" size="30" type="text" value="10" />',
|
29
|
+
@template.text_field(:product, :quantity, :object => @localized)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_text_field_with_decimal_attribute
|
33
|
+
assert_equal '<input id="product_price" name="product[price]" size="30" type="text" value="1,99" />',
|
34
|
+
@template.text_field(:product, :price, :object => @localized)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_text_field_with_date_attribute
|
38
|
+
assert_equal '<input id="product_released_at" name="product[released_at]" size="30" type="text" value="28/02/2011" />',
|
39
|
+
@template.text_field(:product, :released_at, :object => @localized)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_text_field_with_time_attribute
|
43
|
+
assert_equal '<input id="product_last_sale_at" name="product[last_sale_at]" size="30" type="text" value="28/02/2011 13:25:30" />',
|
44
|
+
@template.text_field(:product, :last_sale_at, :object => @localized)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
ActiveRecord::Base.establish_connection(
|
2
|
+
:adapter => "sqlite3",
|
3
|
+
:database => ":memory:"
|
4
|
+
)
|
5
|
+
|
6
|
+
ActiveRecord::Schema.define do
|
7
|
+
self.verbose = false
|
8
|
+
|
9
|
+
create_table :products do |t|
|
10
|
+
t.string :name
|
11
|
+
t.decimal :price
|
12
|
+
t.integer :quantity
|
13
|
+
t.date :released_at
|
14
|
+
t.datetime :updated_at
|
15
|
+
t.timestamp :last_sale_at
|
16
|
+
t.references :supplier
|
17
|
+
t.string :my_precious
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table :suppliers do |t|
|
21
|
+
t.string :name
|
22
|
+
t.decimal :a_decimal
|
23
|
+
end
|
24
|
+
|
25
|
+
create_table :accounts do |t|
|
26
|
+
t.references :supplier
|
27
|
+
t.string :account_number
|
28
|
+
t.decimal :total_money
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class DateParserTest < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@parser = I18n::Alchemy::DateParser
|
6
|
+
@date = Date.new(2011, 12, 31)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_does_not_convert_non_string_objects
|
10
|
+
assert_equal @date, @parser.parse(@date)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_parses_valid_string_dates_with_default_i18n_locale
|
14
|
+
assert_equal "2011-12-31", @parser.parse("12/31/2011")
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_parsers_string_dates_on_current_i18n_locale
|
18
|
+
I18n.with_locale :pt do
|
19
|
+
assert_equal "2011-12-31", @parser.parse("31/12/2011")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_parsers_returns_the_given_string_when_invalid_date
|
24
|
+
assert_equal "31/12/2011", @parser.parse("31/12/2011")
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_does_not_localize_string_values
|
28
|
+
assert_equal "12/31/2011", @parser.localize("12/31/2011")
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_localizes_date_values
|
32
|
+
assert_equal "12/31/2011", @parser.localize(@date)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_localizes_date_values_based_on_current_i18n_locale
|
36
|
+
I18n.with_locale :pt do
|
37
|
+
assert_equal "31/12/2011", @parser.localize(@date)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class NumericParserTest < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@parser = I18n::Alchemy::NumericParser
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_does_not_convert_non_string_objects
|
9
|
+
assert_equal 1.2, @parser.parse(1.2)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_parses_valid_string_numbers
|
13
|
+
assert_equal "1.2", @parser.parse("1.2")
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_parses_string_numbers_with_delimiters
|
17
|
+
assert_equal "1_001.2", @parser.parse("1,001.2")
|
18
|
+
assert_equal "1_000_001.2", @parser.parse("1,000_001.2")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_integers
|
22
|
+
assert_equal 999, @parser.parse(999)
|
23
|
+
assert_equal "999", @parser.parse("999")
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_parses_string_numbers_based_on_current_i18n_locale
|
27
|
+
I18n.with_locale :pt do
|
28
|
+
assert_equal "1.2", @parser.parse("1,2")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_parses_string_numbers_with_delimiters_based_on_current_i18n_locale
|
33
|
+
I18n.with_locale :pt do
|
34
|
+
assert_equal "1_001.2", @parser.parse("1.001,2")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_does_not_localize_string_values
|
39
|
+
assert_equal "1.2", @parser.localize("1.2")
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_localize_numeric_values
|
43
|
+
assert_equal "1.20", @parser.localize(1.2)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_localize_numeric_values_with_delimiters
|
47
|
+
assert_equal "123.20", @parser.localize(123.2)
|
48
|
+
assert_equal "999.27", @parser.localize(999.27)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_localize_numeric_values_with_thousand_separators
|
52
|
+
assert_equal "1,001.20", @parser.localize(1001.2)
|
53
|
+
assert_equal "1,000,001.20", @parser.localize(1_000_001.2)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_localize_numbers_based_on_current_i18n_locale
|
57
|
+
I18n.with_locale :pt do
|
58
|
+
assert_equal "1,20", @parser.localize(1.2)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_localize_numbers_with_delimiters_based_on_current_i18n_locale
|
63
|
+
I18n.with_locale :pt do
|
64
|
+
assert_equal "99,20", @parser.localize(99.2)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_localize_numbers_with_separators_based_on_current_i18n_locale
|
69
|
+
I18n.with_locale :pt do
|
70
|
+
assert_equal "1.001,20", @parser.localize(1_001.2)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,302 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ProxyTest < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@product = Product.new
|
6
|
+
@localized = @product.localized
|
7
|
+
@supplier = Supplier.new
|
8
|
+
@supplier_localized = @supplier.localized
|
9
|
+
|
10
|
+
I18n.locale = :pt
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
I18n.locale = :en
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_delegates_orm_methods_to_target_object
|
18
|
+
assert @product.new_record?
|
19
|
+
assert @localized.save!(:name => "foo", :price => 1.99)
|
20
|
+
assert !@product.new_record?
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_delegates_method_with_block_to_target_object
|
24
|
+
@localized.method_with_block do |attr|
|
25
|
+
assert_equal "called!", attr
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_respond_to
|
30
|
+
assert_respond_to @localized, :price
|
31
|
+
assert_respond_to @localized, :price=
|
32
|
+
assert_respond_to @localized, :name
|
33
|
+
assert_respond_to @localized, :save
|
34
|
+
assert_respond_to @localized, :method_with_block
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_does_not_localize_primary_key
|
38
|
+
@product.id = 1
|
39
|
+
assert_equal 1, @localized.id
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_to_param
|
43
|
+
assert_equal @product.to_param, @localized.to_param
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_does_not_localize_foreign_keys
|
47
|
+
@product.supplier_id = 1
|
48
|
+
assert_equal 1, @localized.supplier_id
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_send
|
52
|
+
@product.name = "Potato"
|
53
|
+
assert_equal "Potato", @localized.send(:name)
|
54
|
+
|
55
|
+
@product.price = 1.88
|
56
|
+
assert_equal "1,88", @localized.send(:price)
|
57
|
+
assert_equal "1,88", @localized.send(:price_before_type_cast)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_try
|
61
|
+
@product.price = 1.99
|
62
|
+
assert_equal "1,99", @localized.try(:price)
|
63
|
+
assert_equal "1,99", @localized.try(:price_before_type_cast)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_try_with_block
|
67
|
+
@localized.try :method_with_block do |attr|
|
68
|
+
assert_equal "called!", attr
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Numeric
|
73
|
+
def test_parses_numeric_attribute_input
|
74
|
+
@localized.price = "1,99"
|
75
|
+
assert_equal 1.99, @product.price
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_localizes_numeric_attribute_output
|
79
|
+
@product.price = 1.88
|
80
|
+
assert_equal "1,88", @localized.price
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_localizes_numeric_attribute_before_type_cast_output
|
84
|
+
@product.price = 1.88
|
85
|
+
assert_equal "1,88", @localized.price_before_type_cast
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_formats_numeric_attribute_output_when_localizing
|
89
|
+
@product.price = 1.3
|
90
|
+
assert_equal "1,30", @localized.price
|
91
|
+
|
92
|
+
@product.price = 2
|
93
|
+
assert_equal "2,00", @localized.price
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_parsers_integer_attribute_input
|
97
|
+
@localized.quantity = "1,0"
|
98
|
+
assert_equal 1, @product.quantity
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_localized_integer_attribute_output
|
102
|
+
@product.quantity = 1.0
|
103
|
+
assert_equal 1, @localized.quantity
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_does_not_localize_other_attribute_input
|
107
|
+
@localized.name = "foo"
|
108
|
+
assert_equal "foo", @product.name
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_does_not_localize_other_attribute_output
|
112
|
+
@product.name = "foo"
|
113
|
+
assert_equal "foo", @localized.name
|
114
|
+
end
|
115
|
+
|
116
|
+
# Date
|
117
|
+
def test_parses_date_attribute_input
|
118
|
+
@localized.released_at = "28/02/2011"
|
119
|
+
assert_equal Date.new(2011, 2, 28), @product.released_at
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_localizes_date_attribute_output
|
123
|
+
@product.released_at = Date.new(2011, 2, 28)
|
124
|
+
assert_equal "28/02/2011", @localized.released_at
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_localizes_date_attribute_before_type_cast_output
|
128
|
+
@product.released_at = Date.new(2011, 2, 28)
|
129
|
+
assert_equal "28/02/2011", @localized.released_at_before_type_cast
|
130
|
+
end
|
131
|
+
|
132
|
+
# DateTime
|
133
|
+
def test_parses_datetime_attribute_input
|
134
|
+
@localized.updated_at = "28/02/2011 13:25:30"
|
135
|
+
assert_equal Time.mktime(2011, 2, 28, 13, 25, 30), @product.updated_at
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_localizes_datetime_attribute_output
|
139
|
+
@product.updated_at = Time.mktime(2011, 2, 28, 13, 25, 30)
|
140
|
+
assert_equal "28/02/2011 13:25:30", @localized.updated_at
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_localizes_datetime_attribute_before_type_cast_output
|
144
|
+
@product.updated_at = Time.mktime(2011, 2, 28, 13, 25, 30)
|
145
|
+
assert_equal "28/02/2011 13:25:30", @localized.updated_at_before_type_cast
|
146
|
+
end
|
147
|
+
|
148
|
+
# Timestamp
|
149
|
+
def test_parses_timestamp_attribute_input
|
150
|
+
@localized.last_sale_at = "28/02/2011 13:25:30"
|
151
|
+
assert_equal Time.mktime(2011, 2, 28, 13, 25, 30), @product.last_sale_at
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_localizes_timestamp_attribute_output
|
155
|
+
@product.last_sale_at = Time.mktime(2011, 2, 28, 13, 25, 30)
|
156
|
+
assert_equal "28/02/2011 13:25:30", @localized.last_sale_at
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_localizes_timestamp_attribute_before_type_cast_output
|
160
|
+
@product.last_sale_at = Time.mktime(2011, 2, 28, 13, 25, 30)
|
161
|
+
assert_equal "28/02/2011 13:25:30", @localized.last_sale_at_before_type_cast
|
162
|
+
end
|
163
|
+
|
164
|
+
# Attributes
|
165
|
+
def test_initializes_proxy_with_attributes
|
166
|
+
@localized = @product.localized(
|
167
|
+
:name => "Banana", :price => "0,99", :released_at => "28/02/2011")
|
168
|
+
|
169
|
+
assert_equal 0.99, @product.price
|
170
|
+
assert_equal "0,99", @localized.price
|
171
|
+
|
172
|
+
assert_equal Date.new(2011, 2, 28), @product.released_at
|
173
|
+
assert_equal "28/02/2011", @localized.released_at
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_initializes_proxy_with_attributes_and_skips_mass_assignment_security_protection_when_without_protection_is_used
|
177
|
+
@localized = @product.localized(attributes_hash, :without_protection => true)
|
178
|
+
if support_assign_attributes_without_protection?
|
179
|
+
assert_equal 'My Precious!', @localized.my_precious
|
180
|
+
else
|
181
|
+
assert_nil @localized.my_precious
|
182
|
+
end
|
183
|
+
assert_equal 1, @localized.quantity
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_assign_attributes
|
187
|
+
@localized.assign_attributes(:price => '1,99')
|
188
|
+
assert_equal "1,99", @localized.price
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_mass_assigning_invalid_attribute
|
192
|
+
assert_raises(ActiveRecord::UnknownAttributeError) do
|
193
|
+
@localized.assign_attributes('i_dont_even_exist' => 40)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_new_with_attr_protected_attributes
|
198
|
+
@localized.assign_attributes(attributes_hash)
|
199
|
+
assert_nil @localized.my_precious
|
200
|
+
assert_equal 1, @localized.quantity
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_assign_attributes_skips_mass_assignment_security_protection_when_without_protection_is_used
|
204
|
+
@localized.assign_attributes(attributes_hash, :without_protection => true)
|
205
|
+
if support_assign_attributes_without_protection?
|
206
|
+
assert_equal 'My Precious!', @localized.my_precious
|
207
|
+
else
|
208
|
+
assert_nil @localized.my_precious
|
209
|
+
end
|
210
|
+
assert_equal 1, @localized.quantity
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_assign_attributes_does_not_change_given_attributes_hash
|
214
|
+
assert_attributes_hash_is_not_changed(attributes = attributes_hash) do
|
215
|
+
@localized.assign_attributes(attributes)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_attributes_assignment
|
220
|
+
@localized.attributes = { :price => '1,99' }
|
221
|
+
assert_equal "1,99", @localized.price
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_attributes_assignment_does_not_change_given_attributes_hash
|
225
|
+
assert_attributes_hash_is_not_changed(attributes = attributes_hash) do
|
226
|
+
@localized.attributes = attributes
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_update_attributes
|
231
|
+
@localized.update_attributes(:price => '2,88')
|
232
|
+
assert_equal '2,88', @localized.price
|
233
|
+
assert_equal 2.88, @product.reload.price
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_update_attributes_does_not_change_given_attributes_hash
|
237
|
+
assert_attributes_hash_is_not_changed(attributes = attributes_hash) do
|
238
|
+
@localized.update_attributes(attributes)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_update_attributes!
|
243
|
+
@localized.update_attributes!(:price => '2,88')
|
244
|
+
assert_equal '2,88', @localized.price
|
245
|
+
assert_equal 2.88, @product.reload.price
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_update_attributes_bang_does_not_change_given_attributes_hash
|
249
|
+
assert_attributes_hash_is_not_changed(attributes = attributes_hash) do
|
250
|
+
@localized.update_attributes!(attributes)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_update_attribute
|
255
|
+
@localized.update_attribute(:price, '2,88')
|
256
|
+
assert_equal '2,88', @localized.price
|
257
|
+
assert_equal 2.88, @product.reload.price
|
258
|
+
end
|
259
|
+
|
260
|
+
# Nested Attributes
|
261
|
+
def test_should_assign_for_nested_attributes_for_collection_association
|
262
|
+
@supplier_localized.assign_attributes(:products_attributes => [{:price => '1,99'}, {:price => '2,93'}])
|
263
|
+
assert_equal 2, @supplier_localized.products.size
|
264
|
+
assert_equal '1,99', @supplier_localized.products.first.localized.price
|
265
|
+
assert_equal '2,93', @supplier_localized.products.last.localized.price
|
266
|
+
end
|
267
|
+
|
268
|
+
def test_should_assign_for_nested_attributes_passing_a_hash_for_collection_with_unique_keys
|
269
|
+
@supplier_localized.assign_attributes(:products_attributes => {"0" => {:price => '2,93', "_destroy"=>"false"}, "1" => {:price => '2,85', "_destroy" => "false"}})
|
270
|
+
prices = @supplier.products.map { |p| p.localized.price }.sort
|
271
|
+
assert_equal ['2,85', '2,93'], prices
|
272
|
+
end
|
273
|
+
|
274
|
+
def test_should_assign_for_nested_attributes_for_one_to_one_association
|
275
|
+
@supplier_localized.assign_attributes(:account_attributes => {:account_number => 10, :total_money => '100,87'})
|
276
|
+
account = @supplier_localized.account
|
277
|
+
assert_equal 10, account.account_number
|
278
|
+
assert_equal '100,87', account.localized.total_money
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_update_attributes_for_nested_attributes
|
282
|
+
@supplier_localized.update_attributes(:account_attributes => {:total_money => '99,87'})
|
283
|
+
assert_equal '99,87', @supplier_localized.account.localized.total_money
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_attributes_assignment_for_nested
|
287
|
+
@supplier_localized.attributes = {:account_attributes => {:total_money => '88,12'}}
|
288
|
+
assert_equal '88,12', @supplier_localized.account.localized.total_money
|
289
|
+
end
|
290
|
+
|
291
|
+
private
|
292
|
+
|
293
|
+
def attributes_hash
|
294
|
+
{ :my_precious => 'My Precious!', :quantity => 1 }
|
295
|
+
end
|
296
|
+
|
297
|
+
def assert_attributes_hash_is_not_changed(attributes)
|
298
|
+
yield
|
299
|
+
assert_equal 1, attributes[:quantity]
|
300
|
+
assert_equal 'My Precious!', attributes[:my_precious]
|
301
|
+
end
|
302
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
module BaseTimeParserTest
|
4
|
+
def test_does_not_convert_non_string_objects
|
5
|
+
assert_equal @time, @parser.parse(@time)
|
6
|
+
end
|
7
|
+
|
8
|
+
# TODO: why so many time differences on the output?
|
9
|
+
def test_parses_valid_string_times_with_default_i18n_locale
|
10
|
+
output_timestamp = if RUBY_VERSION < "1.9"
|
11
|
+
"Sat Dec 31 12:15:45 UTC 2011"
|
12
|
+
else
|
13
|
+
"2011-12-31 12:15:45 UTC"
|
14
|
+
end
|
15
|
+
|
16
|
+
assert_equal output_timestamp, @parser.parse("12/31/2011 12:15:45")
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_parsers_string_times_on_current_i18n_locale
|
20
|
+
I18n.with_locale :pt do
|
21
|
+
output_timestamp = if RUBY_VERSION < "1.9"
|
22
|
+
"Sat Dec 31 12:15:45 UTC 2011"
|
23
|
+
else
|
24
|
+
"2011-12-31 12:15:45 UTC"
|
25
|
+
end
|
26
|
+
|
27
|
+
assert_equal output_timestamp, @parser.parse("31/12/2011 12:15:45")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_parsers_returns_the_given_string_when_invalid_time
|
32
|
+
assert_equal "31/12/2011 12:15:45", @parser.parse("31/12/2011 12:15:45")
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_does_not_localize_string_values
|
36
|
+
assert_equal "12/31/2011 12:15:45", @parser.localize("12/31/2011 12:15:45")
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_localizes_time_values
|
40
|
+
assert_equal "12/31/2011 12:15:45", @parser.localize(@time)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_localizes_time_values_based_on_current_i18n_locale
|
44
|
+
I18n.with_locale :pt do
|
45
|
+
assert_equal "31/12/2011 12:15:45", @parser.localize(@time)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class TimeParserTest < MiniTest::Unit::TestCase
|
51
|
+
def setup
|
52
|
+
@parser = I18n::Alchemy::TimeParser
|
53
|
+
@time = Time.mktime(2011, 12, 31, 12, 15, 45)
|
54
|
+
end
|
55
|
+
|
56
|
+
include BaseTimeParserTest
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
class DateTimeParserTest < MiniTest::Unit::TestCase
|
61
|
+
def setup
|
62
|
+
@parser = I18n::Alchemy::TimeParser
|
63
|
+
@time = DateTime.new(2011, 12, 31, 12, 15, 45)
|
64
|
+
end
|
65
|
+
|
66
|
+
include BaseTimeParserTest
|
67
|
+
end
|
data/test/locale/en.yml
ADDED
data/test/locale/pt.yml
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/setup"
|
3
|
+
Bundler.require :test
|
4
|
+
|
5
|
+
require "minitest/unit"
|
6
|
+
MiniTest::Unit.autorun
|
7
|
+
|
8
|
+
require "i18n_alchemy"
|
9
|
+
require "action_view"
|
10
|
+
|
11
|
+
# Setup I18n after other requires to make sure our locales will override any
|
12
|
+
# ActiveSupport / ActionView defaults.
|
13
|
+
I18n.default_locale = :en
|
14
|
+
I18n.locale = :en
|
15
|
+
I18n.load_path << Dir[File.expand_path("../locale/*.yml", __FILE__)]
|
16
|
+
|
17
|
+
require "db/test_schema"
|
18
|
+
Dir["test/models/*.rb"].each { |file| require File.expand_path(file) }
|
19
|
+
|
20
|
+
class MiniTest::Unit::TestCase
|
21
|
+
# AR 3.0 does not have assign_attributes and without_protection option, so we
|
22
|
+
# are going to skip such tests in this version.
|
23
|
+
def support_assign_attributes_without_protection?
|
24
|
+
@support_assign_attributes ||= ActiveRecord::VERSION::STRING >= "3.1.0"
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: i18n_alchemy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Carlos Antonio da Silva
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: &70234292607060 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70234292607060
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &70234292606460 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3.0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70234292606460
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: i18n
|
38
|
+
requirement: &70234292605940 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0.5'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70234292605940
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: &70234292605400 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.9.2
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70234292605400
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: actionpack
|
60
|
+
requirement: &70234292604880 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '3.0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70234292604880
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: &70234292604220 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 2.10.0
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70234292604220
|
80
|
+
description: I18n date/number parsing/localization
|
81
|
+
email:
|
82
|
+
- carlosantoniodasilva@gmail.com
|
83
|
+
executables: []
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files: []
|
86
|
+
files:
|
87
|
+
- CHANGELOG.md
|
88
|
+
- MIT-LICENSE
|
89
|
+
- README.md
|
90
|
+
- lib/i18n_alchemy/association_parser.rb
|
91
|
+
- lib/i18n_alchemy/attribute.rb
|
92
|
+
- lib/i18n_alchemy/date_parser.rb
|
93
|
+
- lib/i18n_alchemy/numeric_parser.rb
|
94
|
+
- lib/i18n_alchemy/proxy.rb
|
95
|
+
- lib/i18n_alchemy/time_parser.rb
|
96
|
+
- lib/i18n_alchemy/version.rb
|
97
|
+
- lib/i18n_alchemy.rb
|
98
|
+
- test/action_view_test.rb
|
99
|
+
- test/db/test_schema.rb
|
100
|
+
- test/i18n_alchemy/date_parser_test.rb
|
101
|
+
- test/i18n_alchemy/numeric_parser_test.rb
|
102
|
+
- test/i18n_alchemy/proxy_test.rb
|
103
|
+
- test/i18n_alchemy/time_parser_test.rb
|
104
|
+
- test/locale/en.yml
|
105
|
+
- test/locale/pt.yml
|
106
|
+
- test/models/account.rb
|
107
|
+
- test/models/product.rb
|
108
|
+
- test/models/supplier.rb
|
109
|
+
- test/test_helper.rb
|
110
|
+
homepage: ''
|
111
|
+
licenses: []
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
segments:
|
123
|
+
- 0
|
124
|
+
hash: -3439421370757510840
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ! '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
segments:
|
132
|
+
- 0
|
133
|
+
hash: -3439421370757510840
|
134
|
+
requirements: []
|
135
|
+
rubyforge_project: i18n_alchemy
|
136
|
+
rubygems_version: 1.8.17
|
137
|
+
signing_key:
|
138
|
+
specification_version: 3
|
139
|
+
summary: I18n date/number parsing/localization
|
140
|
+
test_files:
|
141
|
+
- test/action_view_test.rb
|
142
|
+
- test/db/test_schema.rb
|
143
|
+
- test/i18n_alchemy/date_parser_test.rb
|
144
|
+
- test/i18n_alchemy/numeric_parser_test.rb
|
145
|
+
- test/i18n_alchemy/proxy_test.rb
|
146
|
+
- test/i18n_alchemy/time_parser_test.rb
|
147
|
+
- test/locale/en.yml
|
148
|
+
- test/locale/pt.yml
|
149
|
+
- test/models/account.rb
|
150
|
+
- test/models/product.rb
|
151
|
+
- test/models/supplier.rb
|
152
|
+
- test/test_helper.rb
|