delocalize 0.4.0 → 1.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.
@@ -0,0 +1,15 @@
1
+ # TODO Rethink: Shouldn't this return numbers instead of reformatted strings?
2
+ module Delocalize
3
+ module Parsers
4
+ class Number
5
+ # Parse numbers removing unneeded characters and replacing decimal separator
6
+ # through I18n. This will return a valid Ruby Numeric value (as String).
7
+ def parse(value)
8
+ return value unless value.is_a?(String)
9
+
10
+ separator, delimiter = I18n.t([:separator, :delimiter], :scope => :'number.format')
11
+ value.gsub(delimiter, '').gsub(separator, '.')
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,15 +1,15 @@
1
1
  module Delocalize
2
2
  class Railtie < Rails::Railtie
3
3
  initializer "delocalize" do |app|
4
- ActiveSupport.on_load :active_record do
5
- require 'delocalize/rails_ext/active_record'
4
+ ActiveSupport.on_load :action_controller do
5
+ # By default, we use ActionController::Parameters provided by strong_parameters. If it's
6
+ # not there, we fall back to our own replacement (Delocalize::Parameters).
7
+ if defined?(ActionController::Parameters)
8
+ ActionController::Parameters.send(:include, Delocalize::ParameterDelocalizing)
9
+ else
10
+ ActionController::Base.send(:include, Delocalize::DelocalizableParameters)
11
+ end
6
12
  end
7
-
8
- ActiveSupport.on_load :action_view do
9
- require 'delocalize/rails_ext/action_view'
10
- end
11
-
12
- require 'delocalize/rails_ext/time_zone'
13
13
  end
14
14
  end
15
15
  end
@@ -0,0 +1,3 @@
1
+ module Delocalize
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ require 'test_helper'
4
+ require 'active_support/time'
5
+
6
+ describe Delocalize::Parsers::DateTime do
7
+ before do
8
+ Time.zone = 'Berlin' # make sure everything works as expected with TimeWithZone
9
+ @time_parser = Delocalize::Parsers::DateTime.new(Time)
10
+ @date_parser = Delocalize::Parsers::DateTime.new(Date)
11
+ end
12
+
13
+ after do
14
+ Timecop.return
15
+ end
16
+
17
+ # date
18
+ it "parses a date from a string" do
19
+ date = Date.civil(2009, 10, 19)
20
+ @date_parser.parse('19. Oktober 2009').must_equal date
21
+ @date_parser.parse('19.10.2009').must_equal date
22
+ end
23
+
24
+ it "parses a date without a year from a string, defaulting to the current year" do
25
+ date = Date.civil(Date.today.year, 10, 19)
26
+ @date_parser.parse('19. Okt.').must_equal date
27
+ @date_parser.parse('19.10.').must_equal date
28
+ end
29
+
30
+ # datetime
31
+ it "parses a datetime from a string" do
32
+ time = Time.zone.local(2009, 3, 1, 12, 0, 0)
33
+ @time_parser.parse('Sonntag, 1. März 2009, 12:00 Uhr').must_equal time
34
+ @time_parser.parse('1. März 2009, 12:00 Uhr').must_equal time
35
+ end
36
+
37
+ it "parses a datetime without a year from a string, defaulting to the current year" do
38
+ time = Time.zone.local(Time.now.year, 3, 1, 12, 0, 0)
39
+ @time_parser.parse('1. März, 12:00 Uhr').must_equal time
40
+ end
41
+
42
+ # time
43
+ it "parses a time from a string, defaulting to the current day" do
44
+ Timecop.freeze(Time.zone.local(2009, 3, 1, 12, 0, 0)) # prevent DST issues
45
+ time = Time.zone.local(2009, 3, 1, 9, 0, 0, 0)
46
+ @time_parser.parse('9:00 Uhr').must_equal time
47
+ end
48
+
49
+ it "doesn't parse date/time-like objects" do
50
+ date = Date.civil(2009, 10, 19)
51
+ time = Time.zone.local(2009, 3, 1, 12, 0, 0)
52
+
53
+ @date_parser.parse(date).must_equal date
54
+ @time_parser.parse(time).must_equal time
55
+ end
56
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ describe Delocalize::Parsers::Number do
4
+ before do
5
+ @parser = Delocalize::Parsers::Number.new
6
+ end
7
+
8
+ it "parses a number from a string" do
9
+ @parser.parse('1.299,99').must_equal '1299.99'
10
+ end
11
+
12
+ it "parses a negative number from a string" do
13
+ @parser.parse('-1.299,99').must_equal '-1299.99'
14
+ end
15
+
16
+ it "parses an integer from a string" do
17
+ @parser.parse('1.299').must_equal '1299'
18
+ end
19
+
20
+ it "parses a negative integer from a string" do
21
+ @parser.parse('-1.299').must_equal '-1299'
22
+ end
23
+
24
+ it "doesn't change a number if it's already a numeric type" do
25
+ @parser.parse(1299.99).must_equal 1299.99
26
+ @parser.parse(-1299.99).must_equal -1299.99
27
+ @parser.parse(1299).must_equal 1299
28
+ @parser.parse(-1299).must_equal -1299
29
+ end
30
+ end
@@ -0,0 +1,171 @@
1
+ require 'test_helper'
2
+
3
+ parameters_classes = [Delocalize::Parameters]
4
+
5
+ if defined?(ActionController::Parameters)
6
+ # FIXME Can this happen automatically, e.g. by loading the Railtie?
7
+ ActionController::Parameters.send(:include, Delocalize::ParameterDelocalizing)
8
+ parameters_classes << ActionController::Parameters
9
+ end
10
+
11
+ parameters_classes.each do |parameters_class|
12
+ describe parameters_class do
13
+ before do
14
+ Time.zone = 'Berlin' # make sure everything works as expected with TimeWithZone
15
+ end
16
+
17
+ it "delocalizes top level params based on the given options" do
18
+ params = parameters_class.new(:released_on => '21. Mai 1986', :available_until => '25. Dezember 2013, 23:59 Uhr', :price => '1.299,99')
19
+
20
+ delocalized_params = params.delocalize(:released_on => :date, :available_until => :time, :price => :number)
21
+
22
+ delocalized_params[:released_on].must_equal Date.civil(1986, 5, 21)
23
+ delocalized_params[:available_until].must_equal Time.zone.local(2013, 12, 25, 23, 59)
24
+ delocalized_params[:price].must_equal '1299.99'
25
+ end
26
+
27
+ it "delocalizes nested params based on the given options" do
28
+ params = parameters_class.new(:product => { :released_on => '21. Mai 1986', :available_until => '25. Dezember 2013, 23:59 Uhr', :price => '1.299,99' })
29
+
30
+ delocalized_params = params.delocalize(:product => { :released_on => :date, :available_until => :time, :price => :number })
31
+
32
+ delocalized_params[:product][:released_on].must_equal Date.civil(1986, 5, 21)
33
+ delocalized_params[:product][:available_until].must_equal Time.zone.local(2013, 12, 25, 23, 59)
34
+ delocalized_params[:product][:price].must_equal '1299.99'
35
+ end
36
+
37
+ it "delocalizes field-for type params based on the given options" do
38
+ params = parameters_class.new(
39
+ :product => {
40
+ variant_attributes: {
41
+ "0" => { :released_on => '21. Mai 1986', :available_until => '25. Dezember 2013, 23:59 Uhr', :price => '1.299,99' },
42
+ "1" => { :released_on => '1. Juni 2001', :available_until => '12. November 2014, 00:00 Uhr', :price => '1.099,01' },
43
+ }
44
+ }
45
+ )
46
+
47
+ delocalized_params = params.delocalize(:product => { :variant_attributes => { :released_on => :date, :available_until => :time, :price => :number } })
48
+
49
+ delocalized_params[:product][:variant_attributes]['0'][:released_on].must_equal Date.civil(1986, 5, 21)
50
+ delocalized_params[:product][:variant_attributes]['0'][:available_until].must_equal Time.zone.local(2013, 12, 25, 23, 59)
51
+ delocalized_params[:product][:variant_attributes]['0'][:price].must_equal '1299.99'
52
+
53
+ delocalized_params[:product][:variant_attributes]['1'][:released_on].must_equal Date.civil(2001, 6, 1)
54
+ delocalized_params[:product][:variant_attributes]['1'][:available_until].must_equal Time.zone.local(2014, 11, 12, 00, 00)
55
+ delocalized_params[:product][:variant_attributes]['1'][:price].must_equal '1099.01'
56
+ end
57
+
58
+ it "delocalizes nested params on the key itself based on the given options" do
59
+ params = parameters_class.new(:product => { :released_on => '21. Mai 1986', :available_until => '25. Dezember 2013, 23:59 Uhr', :price => '1.299,99' })
60
+
61
+ product_params = params[:product].delocalize(:released_on => :date, :available_until => :time, :price => :number)
62
+
63
+ product_params[:released_on].must_equal Date.civil(1986, 5, 21)
64
+ product_params[:available_until].must_equal Time.zone.local(2013, 12, 25, 23, 59)
65
+ product_params[:price].must_equal '1299.99'
66
+ end
67
+
68
+ it "delocalizes deeply nested params for one-to-one based on the given options" do
69
+ params = parameters_class.new(:parent => { :child => { :child_date => '21. Mai 1986', :child_time => '25. Dezember 2013, 23:59 Uhr', :child_number => '1.299,99' } })
70
+
71
+ delocalized_params = params.delocalize(:parent => { :child => { :child_date => :date, :child_time => :time, :child_number => :number } })
72
+
73
+ delocalized_params[:parent][:child][:child_date].must_equal Date.civil(1986, 5, 21)
74
+ delocalized_params[:parent][:child][:child_time].must_equal Time.zone.local(2013, 12, 25, 23, 59)
75
+ delocalized_params[:parent][:child][:child_number].must_equal '1299.99'
76
+ end
77
+
78
+ it "delocalizes deeply nested params for one-to-one on the key itself based on the given options" do
79
+ params = parameters_class.new(:parent => { :child => { :child_date => '21. Mai 1986', :child_time => '25. Dezember 2013, 23:59 Uhr', :child_number => '1.299,99' } })
80
+
81
+ parent_params = params[:parent].delocalize(:child => { :child_date => :date, :child_time => :time, :child_number => :number })
82
+
83
+ parent_params[:child][:child_date].must_equal Date.civil(1986, 5, 21)
84
+ parent_params[:child][:child_time].must_equal Time.zone.local(2013, 12, 25, 23, 59)
85
+ parent_params[:child][:child_number].must_equal '1299.99'
86
+ end
87
+
88
+ it "delocalizes all the things at all the levels of all the types" do
89
+ delocalize_options = {
90
+ :top_level_date => :date,
91
+ :top_level_time => :time,
92
+ :top_level_number => :number,
93
+ :parent => {
94
+ :parent_date => :date,
95
+ :parent_time => :time,
96
+ :parent_number => :number,
97
+ :child => {
98
+ :child_date => :date,
99
+ :child_time => :time,
100
+ :child_number => :number
101
+ }
102
+ }
103
+ }
104
+
105
+ params = parameters_class.new(
106
+ :top_level_date => '21. Mai 1986',
107
+ :top_level_time => '25. Dezember 2013, 23:59 Uhr',
108
+ :top_level_number => '1.299,99',
109
+ :parent => {
110
+ :parent_date => '21. Mai 2004',
111
+ :parent_time => '24. Dezember 2013, 23:59 Uhr',
112
+ :parent_number => '999,99',
113
+ :child => {
114
+ :child_date => '21. Mai 2011',
115
+ :child_time => '31. Dezember 2013, 23:59 Uhr',
116
+ :child_number => '9.999'
117
+ }
118
+ }
119
+ )
120
+
121
+ delocalized_params = params.delocalize(delocalize_options)
122
+
123
+ delocalized_params[:top_level_date].must_equal Date.civil(1986, 5, 21)
124
+ delocalized_params[:top_level_time].must_equal Time.zone.local(2013, 12, 25, 23, 59)
125
+ delocalized_params[:top_level_number].must_equal '1299.99'
126
+
127
+ delocalized_params[:parent][:parent_date].must_equal Date.civil(2004, 5, 21)
128
+ delocalized_params[:parent][:parent_time].must_equal Time.zone.local(2013, 12, 24, 23, 59)
129
+ delocalized_params[:parent][:parent_number].must_equal '999.99'
130
+
131
+ delocalized_params[:parent][:child][:child_date].must_equal Date.civil(2011, 5, 21)
132
+ delocalized_params[:parent][:child][:child_time].must_equal Time.zone.local(2013, 12, 31, 23, 59)
133
+ delocalized_params[:parent][:child][:child_number].must_equal '9999'
134
+ end
135
+
136
+ # TODO Figure out deeply nested params for one-to-many relations.
137
+ # The problem is that one-to-many relations may be given as a hash or an array. Delocalize should
138
+ # be able both cases just fine.
139
+
140
+ it "fails for a non-existent type" do
141
+ params = parameters_class.new(:available_until => '25. Dezember 2013, 23:59 Uhr')
142
+
143
+ ->{ params.delocalize(:available_until => :datetime) }.must_raise(Delocalize::ParserNotFound)
144
+ end
145
+
146
+ it "keeps unconfigured parameters as they are while still delocalizing others" do
147
+ params = parameters_class.new(:released_on => '1986-05-21', :price => '1.299,99')
148
+
149
+ delocalized_params = params.delocalize(:price => :number)
150
+
151
+ delocalized_params[:released_on].must_equal '1986-05-21'
152
+ delocalized_params[:price].must_equal '1299.99'
153
+ end
154
+
155
+ it "doesn't raise when nested params given and which aren't defined in options" do
156
+ params = parameters_class.new(:parent => { :parent_date => '21. Mai 2004' })
157
+
158
+ ## Should not throw an error:
159
+ delocalized_params = params.delocalize({})
160
+ end
161
+
162
+ it "delocalizes arrays" do
163
+ params = parameters_class.new(:location => ['13,456', '51,234'], :interval => ['25. Dezember 2013', '31. Januar 2014'])
164
+
165
+ delocalized_params = params.delocalize(:location => [:number], interval: [:date])
166
+
167
+ delocalized_params[:location].must_equal ['13.456', '51.234']
168
+ delocalized_params[:interval].must_equal [Date.civil(2013, 12, 25), Date.civil(2014, 1, 31)]
169
+ end
170
+ end
171
+ end
@@ -5,21 +5,21 @@ require 'bundler'
5
5
 
6
6
  Bundler.require(:default, :development)
7
7
 
8
- require 'rails/all'
9
- require 'rails/test_help'
8
+ require 'minitest/autorun'
9
+ require 'minitest/spec'
10
+ require 'mocha/setup'
10
11
 
11
- require 'delocalize/rails_ext/action_view'
12
- require 'delocalize/rails_ext/active_record'
13
- require 'delocalize/rails_ext/time_zone'
12
+ require 'rails'
14
13
 
15
14
  de = {
16
15
  :date => {
17
16
  :input => {
18
- :formats => [:long, :short, :default]
17
+ :formats => [:long, :short, :short_with_name, :default]
19
18
  },
20
19
  :formats => {
21
20
  :default => "%d.%m.%Y",
22
- :short => "%e. %b",
21
+ :short => "%e.%m.",
22
+ :short_with_name => "%e. %b.",
23
23
  :long => "%e. %B %Y",
24
24
  :only_day => "%e"
25
25
  },
@@ -65,38 +65,4 @@ tt[:date][:formats][:default] = '%d|%m|%Y'
65
65
  I18n.backend.store_translations :de, de
66
66
  I18n.backend.store_translations :tt, tt
67
67
 
68
- I18n.enforce_available_locales = false
69
68
  I18n.locale = :de
70
-
71
- class NonArProduct
72
- attr_accessor :name, :price, :times_sold,
73
- :cant_think_of_a_sensible_time_field,
74
- :released_on, :published_at
75
- end
76
-
77
- class Product < ActiveRecord::Base
78
- end
79
-
80
- class ProductWithValidation < Product
81
- validates_numericality_of :price
82
- validates_presence_of :price
83
- end
84
-
85
- class ProductWithBusinessValidation < Product
86
- validates_numericality_of :price, :less_than => 10
87
- end
88
-
89
- config = YAML.load_file(File.dirname(__FILE__) + '/database.yml')
90
- ActiveRecord::Base.establish_connection(config['test'])
91
-
92
- ActiveRecord::Base.connection.create_table :products do |t|
93
- t.string :name
94
- t.date :released_on
95
- t.datetime :published_at
96
- t.time :cant_think_of_a_sensible_time_field
97
- t.decimal :price
98
- t.float :weight
99
- t.integer :times_sold
100
- t.decimal :some_value_with_default, :default => 0, :precision => 20, :scale => 2
101
- end
102
-
metadata CHANGED
@@ -1,48 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delocalize
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
5
- prerelease:
4
+ version: 1.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Clemens Kofler
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-08-06 00:00:00.000000000 Z
11
+ date: 2015-11-12 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rails
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
- version: '3.0'
19
+ version: '2'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
- version: '3.0'
26
+ version: '2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mocha
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
30
41
  - !ruby/object:Gem::Dependency
31
42
  name: timecop
32
43
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
44
  requirements:
35
- - - ~>
45
+ - - ">="
36
46
  - !ruby/object:Gem::Version
37
- version: 0.3.5
47
+ version: '0'
38
48
  type: :development
39
49
  prerelease: false
40
50
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
51
  requirements:
43
- - - ~>
52
+ - - ">="
44
53
  - !ruby/object:Gem::Version
45
- version: 0.3.5
54
+ version: '0'
46
55
  description: Delocalize is a tool for parsing localized dates/times and numbers.
47
56
  email: clemens@railway.at
48
57
  executables: []
@@ -50,55 +59,54 @@ extensions: []
50
59
  extra_rdoc_files:
51
60
  - README.markdown
52
61
  files:
53
- - lib/delocalize/i18n_ext.rb
54
- - lib/delocalize/localized_date_time_parser.rb
55
- - lib/delocalize/localized_numeric_parser.rb
56
- - lib/delocalize/rails_ext/action_view.rb
62
+ - MIT-LICENSE
63
+ - README.markdown
64
+ - lib/delocalize.rb
65
+ - lib/delocalize/delocalizable_parameters.rb
66
+ - lib/delocalize/parameter_delocalizing.rb
67
+ - lib/delocalize/parameters.rb
68
+ - lib/delocalize/parsers.rb
69
+ - lib/delocalize/parsers/date_time.rb
70
+ - lib/delocalize/parsers/number.rb
57
71
  - lib/delocalize/rails_ext/action_view_rails3.rb
58
72
  - lib/delocalize/rails_ext/action_view_rails4.rb
59
- - lib/delocalize/rails_ext/active_record.rb
60
73
  - lib/delocalize/rails_ext/active_record_rails3.rb
61
74
  - lib/delocalize/rails_ext/active_record_rails4.rb
62
- - lib/delocalize/rails_ext/time_zone.rb
63
75
  - lib/delocalize/railtie.rb
64
- - lib/delocalize/ruby_ext/date.rb
65
- - lib/delocalize/ruby_ext/datetime.rb
66
- - lib/delocalize/ruby_ext/numeric.rb
67
- - lib/delocalize/ruby_ext/time.rb
68
- - lib/delocalize/ruby_ext.rb
69
- - lib/delocalize.rb
70
- - README.markdown
71
- - MIT-LICENSE
76
+ - lib/delocalize/version.rb
72
77
  - test/database.yml
73
- - test/delocalize_test.rb
78
+ - test/date_time_parser_test.rb
79
+ - test/number_parser_test.rb
80
+ - test/parameters_test.rb
74
81
  - test/test_helper.rb
75
82
  homepage: http://github.com/clemens/delocalize
76
83
  licenses:
77
84
  - MIT
85
+ metadata: {}
78
86
  post_install_message:
79
87
  rdoc_options:
80
- - --charset=UTF-8
88
+ - "--charset=UTF-8"
81
89
  require_paths:
82
90
  - lib
83
91
  required_ruby_version: !ruby/object:Gem::Requirement
84
- none: false
85
92
  requirements:
86
- - - ! '>='
93
+ - - ">="
87
94
  - !ruby/object:Gem::Version
88
95
  version: '0'
89
96
  required_rubygems_version: !ruby/object:Gem::Requirement
90
- none: false
91
97
  requirements:
92
- - - ! '>='
98
+ - - ">="
93
99
  - !ruby/object:Gem::Version
94
100
  version: '0'
95
101
  requirements: []
96
102
  rubyforge_project:
97
- rubygems_version: 1.8.23
103
+ rubygems_version: 2.4.5.1
98
104
  signing_key:
99
- specification_version: 3
105
+ specification_version: 4
100
106
  summary: Localized date/time and number parsing
101
107
  test_files:
102
108
  - test/database.yml
103
- - test/delocalize_test.rb
109
+ - test/date_time_parser_test.rb
110
+ - test/number_parser_test.rb
111
+ - test/parameters_test.rb
104
112
  - test/test_helper.rb