time_of_day_attr 1.0.1 → 2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e68d3a3113ec2f822baaf494be19917961776bb
4
- data.tar.gz: 55033d8269193c077a111f956e0f66c45a185eb2
3
+ metadata.gz: 3c2d0f7310864cfe4dc2da656253d4fdc657c03d
4
+ data.tar.gz: 83f2e0bd9b341836d29921fd9eb9b08218696227
5
5
  SHA512:
6
- metadata.gz: 65715383e95ff76d0b793e14d242200b42b9ef24042134619a3f3ea14e49c82ac80b483a57d73eedb7c40d9a46d31193dc777b985f724c9f8f3ba1fb92556506
7
- data.tar.gz: f013b80172f9d1260b5cfe52a9d7fbd6bff9d83468ec11f2e770faca123f856cec8ad475084af4beba9bd174a953e9fd6a573c1207dda54c31bacb681b1b49d9
6
+ metadata.gz: 8bae930ff5660092fdf4b79c6e723445982dba160fab611528c3e42699ef0c827f15d9671196085b8e9154d8b40e95393c18a4273359d685fd7f9a934897d208
7
+ data.tar.gz: 79641b79ff5de0ab50312f5871255411eb448b6eb1e5833e2c81a3beabc9c6ce059a6f91d33de33ad8666dc4d87a92bab5a255807c35de11dbced73579f3cef2
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Time of day attributes for your Rails model
2
2
  [![Gem Version](https://badge.fury.io/rb/time_of_day_attr.png)](http://badge.fury.io/rb/time_of_day_attr) [![Code Climate](https://codeclimate.com/github/clemenst/time_of_day_attr.png)](https://codeclimate.com/github/clemenst/time_of_day_attr) [![License](https://img.shields.io/npm/l/express.svg?style=flat)](http://clemenst.mit-license.org)
3
3
 
4
- This ruby gem converts time of day to seconds since midnight and back. The seconds value is stored in the database and can be used for calculations and validations.
4
+ This ruby gem converts time of day to seconds since midnight and back. The seconds value is stored in the database and can be used for calculations and validations.
5
5
 
6
6
  ## Installation
7
7
 
@@ -75,6 +75,37 @@ TimeOfDayAttr.l(business_hour.opening, format: :custom)
75
75
  => '09-00'
76
76
  ```
77
77
 
78
+ ### Prepending
79
+
80
+ If you want to process the converted value in your model, you can use the prepend option:
81
+
82
+ ```ruby
83
+ class BusinessHour < ActiveRecord::Base
84
+ attr_reader :tracked_opening, :tracked_closing
85
+
86
+ time_of_day_attr :opening
87
+ time_of_day_attr :closing, prepend: true
88
+
89
+ def opening=(value)
90
+ @tracked_opening = value
91
+ super(value)
92
+ end
93
+
94
+ def closing=(value)
95
+ @tracked_closing = value
96
+ super(value)
97
+ end
98
+ end
99
+ ```
100
+
101
+ ```ruby
102
+ business_hour = BusinessHour.new(opening: '9', closing: '9')
103
+ business_hour.tracked_opening
104
+ => '9'
105
+ business_hour.tracked_closing
106
+ => 32400
107
+ ```
108
+
78
109
  ### time of day field
79
110
 
80
111
  To get a text field with the converted value:
data/Rakefile CHANGED
@@ -20,9 +20,6 @@ RDoc::Task.new(:rdoc) do |rdoc|
20
20
  rdoc.rdoc_files.include('lib/**/*.rb')
21
21
  end
22
22
 
23
-
24
-
25
-
26
23
  Bundler::GemHelper.install_tasks
27
24
 
28
25
  require 'rake/testtask'
@@ -34,5 +31,4 @@ Rake::TestTask.new(:test) do |t|
34
31
  t.verbose = false
35
32
  end
36
33
 
37
-
38
- task :default => :test
34
+ task default: :test
@@ -1,35 +1,32 @@
1
+ require 'active_record'
2
+
1
3
  module TimeOfDayAttr
2
4
  module ActiveRecordExt
3
5
  extend ActiveSupport::Concern
4
6
 
5
7
  module ClassMethods
6
-
7
8
  def time_of_day_attr(*attrs)
8
9
  options = attrs.extract_options!
9
- options[:formats] ||= [:default, :hour]
10
- attrs.each do |attr|
11
- define_method("#{attr}=") do |value|
12
- if value.is_a?(String)
13
- delocalized_values = options[:formats].map do |format|
14
- begin
15
- TimeOfDayAttr.delocalize(value, format: format)
16
- rescue ArgumentError => e
17
- if 'argument out of range' == e.message
18
- super(nil)
19
- return
20
- end
21
- nil
22
- end
10
+
11
+ writers = Module.new do
12
+ attrs.each do |attr|
13
+ define_method("#{attr}=") do |value|
14
+ if value.is_a?(String)
15
+ delocalized_value = TimeOfDayAttr.delocalize(value, options)
16
+ super(delocalized_value)
17
+ else
18
+ super(value)
23
19
  end
24
- delocalized_value = delocalized_values.compact.first
25
- super(delocalized_value)
26
- else
27
- super(value)
28
20
  end
29
21
  end
30
22
  end
23
+
24
+ if options[:prepend]
25
+ prepend writers
26
+ else
27
+ include writers
28
+ end
31
29
  end
32
-
33
30
  end
34
31
  end
35
32
  end
@@ -1,15 +1,18 @@
1
+ require 'action_view'
2
+
1
3
  module TimeOfDayAttr
2
4
  module FormBuilderExt
3
5
  extend ActiveSupport::Concern
4
6
 
5
7
  def time_of_day_field(method, options = {})
6
- unless options[:value]
7
- value = object.send(method)
8
- options[:value] = TimeOfDayAttr.localize(value, options.extract!(:format, :omit_minutes_at_full_hour))
8
+ options[:value] ||= begin
9
+ value = object.public_send(method)
10
+ TimeOfDayAttr.localize(value, options.extract!(:format, :omit_minutes_at_full_hour))
9
11
  end
10
12
  text_field(method, options)
11
13
  end
12
-
13
14
  end
14
15
  end
15
- ActionView::Helpers::FormBuilder.send(:include, TimeOfDayAttr::FormBuilderExt)
16
+ ActiveSupport.on_load :action_view do
17
+ ActionView::Helpers::FormBuilder.send(:include, TimeOfDayAttr::FormBuilderExt)
18
+ end
@@ -0,0 +1,17 @@
1
+ module TimeOfDayAttr
2
+ Seconds = Struct.new(:value) do
3
+ def to_time_of_day(time_format)
4
+ # Switch to beginning of year to prevent wrong conversion on the day of time change
5
+ # see https://en.wikipedia.org/wiki/Daylight_saving_time
6
+ time = Time.now.beginning_of_year.at_midnight + value.seconds
7
+
8
+ time_of_day = time.strftime(time_format)
9
+
10
+ if 24.hours.to_i == value
11
+ time_of_day.gsub(' 0', '24')
12
+ else
13
+ time_of_day
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ module TimeOfDayAttr
2
+ TimeOfDay = Struct.new(:value) do
3
+ def to_seconds(time_format)
4
+ time = Time.strptime(value, time_format)
5
+ # Switch to beginning of year to prevent wrong conversion on the day of time change
6
+ # see https://en.wikipedia.org/wiki/Daylight_saving_time
7
+ time = time.change(month: 1, day: 1)
8
+
9
+ seconds = time.seconds_since_midnight.to_i
10
+
11
+ if seconds.zero? && value.starts_with?('24')
12
+ 24.hours.to_i
13
+ else
14
+ seconds
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,3 +1,3 @@
1
1
  module TimeOfDayAttr
2
- VERSION = '1.0.1'
2
+ VERSION = '2'.freeze
3
3
  end
@@ -1,52 +1,51 @@
1
+ require 'time_of_day_attr/time_of_day'
2
+ require 'time_of_day_attr/seconds'
1
3
  require 'time_of_day_attr/active_record_ext'
2
- require 'action_view'
3
4
  require 'time_of_day_attr/form_builder_ext'
4
5
 
5
- files = Dir[File.join(File.dirname(__FILE__), '../config/locales/*.yml')]
6
- I18n.load_path.concat(files)
6
+ formats = Dir[File.join(File.dirname(__FILE__), '../config/locales/*.yml')]
7
+ I18n.load_path.concat(formats)
7
8
 
8
9
  module TimeOfDayAttr
10
+ DEFAULT_FORMATS = [:default, :hour].freeze
9
11
 
10
12
  class << self
11
-
12
13
  def delocalize(value, options = {})
13
- format = options[:format] || :default
14
- format = translate_format(format) if format.is_a?(Symbol)
15
- time = Time.strptime(value, format).change(month: 1, day: 1)
16
- seconds = time.seconds_since_midnight.to_i
17
- if seconds.zero? && value.starts_with?('24')
18
- 24.hours.to_i
19
- else
20
- seconds
14
+ time_of_day = TimeOfDay.new(value)
15
+
16
+ formats = options[:formats] || DEFAULT_FORMATS
17
+
18
+ delocalized_values = formats.map do |format|
19
+ begin
20
+ return time_of_day.to_seconds(time_format(format))
21
+ rescue ArgumentError => e
22
+ return nil if e.message.include?('out of range')
23
+ next
24
+ end
21
25
  end
26
+
27
+ delocalized_values.compact.first
22
28
  end
23
29
 
24
30
  def localize(value, options = {})
25
31
  return value unless value.respond_to?(:seconds)
26
- format = options[:format] || :default
27
- format = translate_format(format) if format.is_a?(Symbol)
28
- # Switch to beginning of year to prevent wrong time on the day of time change
29
- # see https://en.wikipedia.org/wiki/Daylight_saving_time
30
- time = Time.now.beginning_of_year.at_midnight + value.seconds
31
- time_of_day = time.strftime(format)
32
- if 24.hours.to_i == value
33
- time_of_day.gsub!(' 0', '24')
34
- end
35
- if options[:omit_minutes_at_full_hour]
36
- if time_of_day.end_with?('00')
37
- time_of_day = time_of_day[0...-3]
38
- end
39
- end
40
- time_of_day
32
+
33
+ format = options[:format] || DEFAULT_FORMATS.first
34
+
35
+ time_of_day = Seconds.new(value).to_time_of_day(time_format(format))
36
+
37
+ omit_minutes = options[:omit_minutes_at_full_hour] && time_of_day.end_with?('00')
38
+
39
+ omit_minutes ? time_of_day[0...-3] : time_of_day
41
40
  end
42
- alias :l :localize
41
+ alias l localize
43
42
 
44
43
  private
45
44
 
46
- def translate_format(format)
47
- I18n.translate("time_of_day.formats.#{format}")
48
- end
45
+ def time_format(format)
46
+ translate = format.is_a?(Symbol)
49
47
 
48
+ translate ? I18n.translate("time_of_day.formats.#{format}") : format
49
+ end
50
50
  end
51
-
52
51
  end
@@ -0,0 +1,64 @@
1
+ require 'test_helper'
2
+ require 'active_record'
3
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
4
+ require_relative 'schema'
5
+ require_relative 'models/business_hour'
6
+
7
+ class ActiveRecordExtTest < ActiveSupport::TestCase
8
+ context 'time of day value' do
9
+ setup do
10
+ @business_hour = BusinessHour.new(opening: '9:00', closing: '17:00')
11
+ end
12
+
13
+ should 'be converted to seconds since midnight' do
14
+ assert_equal 32_400, @business_hour.opening
15
+ assert_equal 61_200, @business_hour.closing
16
+ end
17
+ end
18
+
19
+ context 'hour formatted time of day value' do
20
+ setup do
21
+ @business_hour = BusinessHour.new(opening: '9', closing: '17')
22
+ end
23
+
24
+ should 'be converted to seconds since midnight' do
25
+ assert_equal 32_400, @business_hour.opening
26
+ assert_equal 61_200, @business_hour.closing
27
+ end
28
+ end
29
+
30
+ context 'unsupported time of day value' do
31
+ setup do
32
+ @business_hour = BusinessHour.new(opening: 55_800)
33
+ @business_hour.opening = 'Nine'
34
+ end
35
+
36
+ should 'be converted to nil' do
37
+ assert_nil @business_hour.opening
38
+ end
39
+ end
40
+
41
+ context 'non string value' do
42
+ setup do
43
+ @business_hour = BusinessHour.new(opening: 55_800)
44
+ end
45
+
46
+ should 'not be converted' do
47
+ assert_equal 55_800, @business_hour.opening
48
+ end
49
+ end
50
+
51
+ context 'prepend option' do
52
+ setup do
53
+ @business_hour = BusinessHour.new(opening: '9', closing: '9')
54
+ end
55
+
56
+ should 'be supported' do
57
+ assert_equal '9', @business_hour.tracked_opening
58
+ assert_equal 32_400, @business_hour.opening
59
+
60
+ assert_equal 32_400, @business_hour.tracked_closing
61
+ assert_equal 32_400, @business_hour.closing
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,16 @@
1
1
  class BusinessHour < ActiveRecord::Base
2
- time_of_day_attr :opening, :closing
2
+ attr_reader :tracked_opening, :tracked_closing
3
+
4
+ time_of_day_attr :opening
5
+ time_of_day_attr :closing, prepend: true
6
+
7
+ def opening=(value)
8
+ @tracked_opening = value
9
+ super(value)
10
+ end
11
+
12
+ def closing=(value)
13
+ @tracked_closing = value
14
+ super(value)
15
+ end
3
16
  end
data/test/schema.rb CHANGED
@@ -1,8 +1,7 @@
1
1
  ActiveRecord::Migration.verbose = false
2
2
 
3
3
  ActiveRecord::Schema.define do
4
-
5
- create_table :business_hours, :force => true do |t|
4
+ create_table :business_hours, force: true do |t|
6
5
  t.integer :opening
7
6
  t.integer :closing
8
7
  end
data/test/test_helper.rb CHANGED
@@ -1,12 +1,5 @@
1
- # Configure Rails Environment
2
- ENV["RAILS_ENV"] = "test"
1
+ ENV['RAILS_ENV'] = 'test'
3
2
 
4
- require 'active_record'
5
3
  require 'minitest/autorun'
4
+ require 'shoulda/context'
6
5
  require 'time_of_day_attr'
7
-
8
- ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
9
-
10
- require File.expand_path('../schema', __FILE__)
11
-
12
- Dir["#{File.dirname(__FILE__)}/models/**/*.rb"].each { |f| require f }
@@ -1,71 +1,43 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class TimeOfDayAttrTest < ActiveSupport::TestCase
4
-
5
- test 'delocalize time of day' do
6
- assert_equal 36000, TimeOfDayAttr.delocalize('10:00')
7
- assert_equal 55800, TimeOfDayAttr.delocalize('15:30')
8
- assert_equal 61140, TimeOfDayAttr.delocalize('16:59')
9
- assert_equal 32400, TimeOfDayAttr.delocalize('9:00')
10
- assert_equal 32400, TimeOfDayAttr.delocalize('09:00')
11
- assert_equal 32400, TimeOfDayAttr.delocalize('9', format: :hour)
4
+ context '::localize' do
5
+ should 'convert seconds to time of day' do
6
+ assert_equal ' 9:00', TimeOfDayAttr.localize(32_400)
7
+ assert_equal '14:45', TimeOfDayAttr.localize(53_100)
8
+ end
9
+
10
+ should 'omit minutes at full hour' do
11
+ assert_equal ' 9', TimeOfDayAttr.localize(32_400, omit_minutes_at_full_hour: true)
12
+ assert_equal '14', TimeOfDayAttr.localize(50_400, omit_minutes_at_full_hour: true)
13
+ assert_equal '14:45', TimeOfDayAttr.localize(53_100, omit_minutes_at_full_hour: true)
14
+ end
15
+
16
+ should 'convert nil to nil' do
17
+ assert_nil TimeOfDayAttr.localize(nil)
18
+ end
19
+
20
+ should 'support 24 hours' do
21
+ assert_equal ' 0:00', TimeOfDayAttr.localize(0)
22
+ assert_equal '24:00', TimeOfDayAttr.localize(86_400)
23
+ assert_equal ' 0', TimeOfDayAttr.localize(0, omit_minutes_at_full_hour: true)
24
+ assert_equal '24', TimeOfDayAttr.localize(86_400, omit_minutes_at_full_hour: true)
25
+ end
26
+ end
27
+
28
+ context '::delocaize' do
29
+ should 'convert time of day to seconds' do
30
+ assert_equal 36_000, TimeOfDayAttr.delocalize('10:00')
31
+ assert_equal 55_800, TimeOfDayAttr.delocalize('15:30')
32
+ assert_equal 61_140, TimeOfDayAttr.delocalize('16:59')
33
+ assert_equal 32_400, TimeOfDayAttr.delocalize('9:00')
34
+ assert_equal 32_400, TimeOfDayAttr.delocalize('09:00')
35
+ assert_equal 32_400, TimeOfDayAttr.delocalize('9', formats: [:hour])
36
+ end
37
+
38
+ should 'convert out of range time of day to nil' do
39
+ assert_nil TimeOfDayAttr.delocalize('25:00')
40
+ assert_nil TimeOfDayAttr.delocalize('24:30')
41
+ end
12
42
  end
13
-
14
- test 'localize time of day' do
15
- assert_equal ' 9:00', TimeOfDayAttr.localize(32400)
16
- assert_equal '14:45', TimeOfDayAttr.localize(53100)
17
- end
18
-
19
- test 'localize time of day and omit minutes at full hour' do
20
- assert_equal ' 9', TimeOfDayAttr.localize(32400, omit_minutes_at_full_hour: true)
21
- assert_equal '14', TimeOfDayAttr.localize(50400, omit_minutes_at_full_hour: true)
22
- assert_equal '14:45', TimeOfDayAttr.localize(53100, omit_minutes_at_full_hour: true)
23
- end
24
-
25
- test 'localizing nil should return nil' do
26
- assert_nil TimeOfDayAttr.localize(nil)
27
- end
28
-
29
- test 'time of day attr setter should delocalize value' do
30
- business_hour = BusinessHour.new(opening: '9:00', closing: '17:00')
31
- assert_equal 32400, business_hour.opening
32
- assert_equal 61200, business_hour.closing
33
- end
34
-
35
- test 'time of day attr setter should delocalize hour formatted value' do
36
- business_hour = BusinessHour.new(opening: '9', closing: '17')
37
- assert_equal 32400, business_hour.opening
38
- assert_equal 61200, business_hour.closing
39
- end
40
-
41
- test 'time of day attr setter should ignore invalid formats' do
42
- business_hour = BusinessHour.new(opening: 'Nine', closing: 'Five')
43
- assert_nil business_hour.opening
44
- assert_nil business_hour.closing
45
- business_hour.opening = '9'
46
- assert_equal 32400, business_hour.opening
47
- business_hour.opening = 'Nine'
48
- assert_nil business_hour.opening
49
- business_hour.opening = '9:30'
50
- assert_equal 34200, business_hour.opening
51
- business_hour.opening = 55800
52
- assert_equal 55800, business_hour.opening
53
- business_hour.opening = nil
54
- assert_nil business_hour.opening
55
- business_hour.opening = '25:00'
56
- assert_nil business_hour.opening
57
- business_hour.opening = '24:30'
58
- assert_nil business_hour.opening
59
- end
60
-
61
- test '24 should be usable' do
62
- business_hour = BusinessHour.new(opening: '0', closing: '24')
63
- assert_equal 0, business_hour.opening
64
- assert_equal 86400, business_hour.closing
65
- assert_equal ' 0:00', TimeOfDayAttr.localize(business_hour.opening)
66
- assert_equal '24:00', TimeOfDayAttr.localize(business_hour.closing)
67
- assert_equal ' 0', TimeOfDayAttr.localize(business_hour.opening, omit_minutes_at_full_hour: true)
68
- assert_equal '24', TimeOfDayAttr.localize(business_hour.closing, omit_minutes_at_full_hour: true)
69
- end
70
-
71
43
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: time_of_day_attr
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: '2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clemens Teichmann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-03 00:00:00.000000000 Z
11
+ date: 2017-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -54,13 +54,17 @@ files:
54
54
  - lib/time_of_day_attr.rb
55
55
  - lib/time_of_day_attr/active_record_ext.rb
56
56
  - lib/time_of_day_attr/form_builder_ext.rb
57
+ - lib/time_of_day_attr/seconds.rb
58
+ - lib/time_of_day_attr/time_of_day.rb
57
59
  - lib/time_of_day_attr/version.rb
60
+ - test/active_record_ext_test.rb
58
61
  - test/models/business_hour.rb
59
62
  - test/schema.rb
60
63
  - test/test_helper.rb
61
64
  - test/time_of_day_attr_test.rb
62
65
  homepage: https://github.com/clemenst/time_of_day_attr
63
- licenses: []
66
+ licenses:
67
+ - MIT
64
68
  metadata: {}
65
69
  post_install_message:
66
70
  rdoc_options: []
@@ -78,12 +82,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
82
  version: '0'
79
83
  requirements: []
80
84
  rubyforge_project:
81
- rubygems_version: 2.5.2
85
+ rubygems_version: 2.6.8
82
86
  signing_key:
83
87
  specification_version: 4
84
88
  summary: Time of day attributes for your Rails model
85
89
  test_files:
86
90
  - test/schema.rb
87
91
  - test/models/business_hour.rb
92
+ - test/active_record_ext_test.rb
88
93
  - test/time_of_day_attr_test.rb
89
94
  - test/test_helper.rb