date_values 0.1.3 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 18c625b8766c99ee4e063b2d2b756f68702d7468301cf0e14cb61c29647bc97e
4
- data.tar.gz: cc21e80e920a5590109a62894d362b541f5f7362835f7d5113980b20bc28842f
3
+ metadata.gz: f294856b7f5149ded52770b4d43d003b5cac6e8ee533f81ec003ac04caf9988b
4
+ data.tar.gz: 8c1f6046926d15cda1a01e55f89e2975b92e6cf515bbc21cb0b6892d816bf93b
5
5
  SHA512:
6
- metadata.gz: 3ea359a67138a64040d1fc62a9288c3862665f636db9e1651697ec6527390e1e53cb002f87745df2189b8eba8944f104e127b620af032be0e92d5a5d707f77a2
7
- data.tar.gz: f5a8b524c53566ee986a3eea6bf28d08e889a428d15b7ae48f04443d46108ee7b882391adc82bc597af10338ef071ec9ecb83dc6812718d67ef332c5065432eb
6
+ metadata.gz: 05e23c3cd91ddda9dcdf5ae63e81dd89c7a6bfd5150dab2893231ebe63c12bc64023cae0667c296e4e88db2dd5869ebdab39245370291cb29cbb9b2d906ad3e3
7
+ data.tar.gz: 28e82e5dc12f33c6e8af8b546338636ef2f6cda3273a2957bf7f86dcb4bb4a6074a4e2376c1c0ed0600f19e98b2783661710c8882b066eb05d3d9c1aa359aea8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.0] - 2026-03-20
4
+
5
+ - **Breaking**: Rails integration extracted to [date_values-rails](https://github.com/ursm/date_values-rails). `require 'date_values/rails'` now requires installing `date_values-rails` gem.
6
+
7
+ ## [0.1.4] - 2026-03-20
8
+
9
+ - Cast returns `nil` for invalid input instead of raising, following Rails convention
10
+ - Add `date_value` validator to distinguish "invalid input" from "no input"
11
+ - `#inspect` now uses `#<ClassName value>` format following Ruby convention
12
+ - Works with Rails standard validators (`comparison`, `inclusion`, `exclusion`)
13
+
3
14
  ## [0.1.3] - 2026-03-20
4
15
 
5
16
  - Fix ActiveRecord type registration — use `ActiveSupport.on_load(:active_record)` to register types regardless of load order
data/README.md CHANGED
@@ -24,27 +24,31 @@ ym = YearMonth.new(2026, 3)
24
24
  ym.to_s # => "2026-03"
25
25
  ym.to_date # => #<Date: 2026-03-01>
26
26
 
27
- YearMonth.from(Date.today) # => YearMonth[2026-03]
28
- YearMonth.parse('2026-03') # => YearMonth[2026-03]
27
+ YearMonth.from(Date.today) # => #<DateValues::YearMonth 2026-03>
28
+ YearMonth.parse('2026-03') # => #<DateValues::YearMonth 2026-03>
29
+ YearMonth.parse('2026/3') # also works
29
30
 
30
- ym + 1 # => YearMonth[2026-04]
31
- ym - 1 # => YearMonth[2026-02]
31
+ ym + 1 # => #<DateValues::YearMonth 2026-04>
32
+ ym - 1 # => #<DateValues::YearMonth 2026-02>
32
33
  YearMonth.new(2026, 3) - YearMonth.new(2025, 1) # => 14
33
34
 
34
35
  # Range support
35
36
  (YearMonth.new(2026, 1)..YearMonth.new(2026, 3)).to_a
36
- # => [YearMonth[2026-01], YearMonth[2026-02], YearMonth[2026-03]]
37
+ # => [#<DateValues::YearMonth 2026-01>, #<DateValues::YearMonth 2026-02>, #<DateValues::YearMonth 2026-03>]
37
38
  ```
38
39
 
39
40
  ### MonthDay
40
41
 
42
+ String representation uses ISO 8601 `--MM-DD` format (year omitted):
43
+
41
44
  ```ruby
42
45
  md = MonthDay.new(3, 19)
43
46
  md.to_s # => "--03-19"
44
47
  md.to_date(2026) # => #<Date: 2026-03-19>
45
48
 
46
- MonthDay.from(Date.today) # => MonthDay[--03-20]
47
- MonthDay.parse('--03-19') # => MonthDay[--03-19]
49
+ MonthDay.from(Date.today) # => #<DateValues::MonthDay --03-20>
50
+ MonthDay.parse('--03-19') # => #<DateValues::MonthDay --03-19>
51
+ MonthDay.parse('3/19') # also works
48
52
 
49
53
  # Range membership
50
54
  summer = MonthDay.new(6, 1)..MonthDay.new(8, 31)
@@ -59,8 +63,8 @@ tod.to_s # => "14:30"
59
63
 
60
64
  TimeOfDay.new(14, 30, 45).to_s # => "14:30:45"
61
65
 
62
- TimeOfDay.from(Time.now) # => TimeOfDay[14:30]
63
- TimeOfDay.parse('14:30') # => TimeOfDay[14:30]
66
+ TimeOfDay.from(Time.now) # => #<DateValues::TimeOfDay 14:30>
67
+ TimeOfDay.parse('14:30') # => #<DateValues::TimeOfDay 14:30>
64
68
 
65
69
  # Range membership
66
70
  business_hours = TimeOfDay.new(9, 0)..TimeOfDay.new(17, 0)
@@ -90,61 +94,7 @@ end
90
94
 
91
95
  ## Rails Integration
92
96
 
93
- Opt-in ActiveModel type casting for ActiveRecord attributes:
94
-
95
- ```ruby
96
- require 'date_values/rails'
97
-
98
- class Shop < ApplicationRecord
99
- attribute :billing_month, :year_month # string column "2026-03"
100
- attribute :anniversary, :month_day # string column "--03-19"
101
- attribute :opens_at, :time_of_day # string or time column
102
- end
103
- ```
104
-
105
- Values are automatically serialized in queries:
106
-
107
- ```ruby
108
- Shop.where(billing_month: YearMonth.new(2026, 3))
109
- # SELECT * FROM shops WHERE billing_month = '2026-03'
110
- ```
111
-
112
- ### I18n / `l` Helper
113
-
114
- All classes implement `#strftime`, and the Rails integration extends `I18n.l` to support them. Define formats in your locale files:
115
-
116
- ```yaml
117
- # config/locales/en.yml
118
- en:
119
- year_month:
120
- formats:
121
- default: '%B %Y'
122
- month_day:
123
- formats:
124
- default: '%B %-d'
125
- time_of_day:
126
- formats:
127
- default: '%-I:%M %p'
128
- ```
129
-
130
- ```yaml
131
- # config/locales/ja.yml
132
- ja:
133
- year_month:
134
- formats:
135
- default: '%Y年%-m月'
136
- month_day:
137
- formats:
138
- default: '%-m月%-d日'
139
- time_of_day:
140
- formats:
141
- default: '%-H時%M分'
142
- ```
143
-
144
- ```ruby
145
- I18n.l YearMonth.new(2026, 3), locale: :en # => "March 2026"
146
- I18n.l YearMonth.new(2026, 3), locale: :ja # => "2026年3月"
147
- ```
97
+ See [date_values-rails](https://github.com/ursm/date_values-rails) for ActiveModel/ActiveRecord type casting, validation, and I18n support.
148
98
 
149
99
  ## License
150
100
 
@@ -18,10 +18,11 @@ module DateValues
18
18
  end
19
19
 
20
20
  def self.parse(str)
21
- raise ArgumentError, "invalid MonthDay: #{str}" unless str.match?(/\A--\d{2}-\d{2}\z/)
22
-
23
- month, day = str[2..].split('-').map(&:to_i)
24
- new(month, day)
21
+ case str
22
+ when /\A--(\d{1,2})-(\d{1,2})\z/ then new($1.to_i, $2.to_i)
23
+ when /\A(\d{1,2})[\/\-](\d{1,2})\z/ then new($1.to_i, $2.to_i)
24
+ else raise ArgumentError, "invalid MonthDay: #{str}"
25
+ end
25
26
  end
26
27
 
27
28
  def <=>(other)
@@ -44,7 +45,7 @@ module DateValues
44
45
  end
45
46
 
46
47
  def inspect
47
- "MonthDay[#{self}]"
48
+ "#<DateValues::MonthDay #{self}>"
48
49
  end
49
50
 
50
51
  private
@@ -42,7 +42,7 @@ module DateValues
42
42
  end
43
43
 
44
44
  def inspect
45
- "TimeOfDay[#{self}]"
45
+ "#<DateValues::TimeOfDay #{self}>"
46
46
  end
47
47
  end
48
48
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DateValues
4
- VERSION = '0.1.3'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -17,10 +17,10 @@ module DateValues
17
17
  end
18
18
 
19
19
  def self.parse(str)
20
- raise ArgumentError, "invalid YearMonth: #{str}" unless str.match?(/\A\d{4}-\d{2}\z/)
21
-
22
- year, month = str.split('-').map(&:to_i)
23
- new(year, month)
20
+ case str
21
+ when /\A(\d{4})[\/\-](\d{1,2})\z/ then new($1.to_i, $2.to_i)
22
+ else raise ArgumentError, "invalid YearMonth: #{str}"
23
+ end
24
24
  end
25
25
 
26
26
  def <=>(other)
@@ -62,7 +62,7 @@ module DateValues
62
62
  end
63
63
 
64
64
  def inspect
65
- "YearMonth[#{self}]"
65
+ "#<DateValues::YearMonth #{self}>"
66
66
  end
67
67
  end
68
68
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: date_values
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keita Urashima
@@ -21,16 +21,10 @@ files:
21
21
  - Rakefile
22
22
  - lib/date_values.rb
23
23
  - lib/date_values/month_day.rb
24
- - lib/date_values/rails.rb
25
- - lib/date_values/rails/i18n_backend.rb
26
- - lib/date_values/rails/month_day_type.rb
27
- - lib/date_values/rails/time_of_day_type.rb
28
- - lib/date_values/rails/year_month_type.rb
29
24
  - lib/date_values/time_of_day.rb
30
25
  - lib/date_values/version.rb
31
26
  - lib/date_values/year_month.rb
32
27
  - sig/date_values.rbs
33
- - sig/date_values/rails.rbs
34
28
  homepage: https://github.com/ursm/date_values
35
29
  licenses:
36
30
  - MIT
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DateValues
4
- module Rails
5
- module I18nBackend
6
- TYPES = {
7
- DateValues::YearMonth => :year_month,
8
- DateValues::MonthDay => :month_day,
9
- DateValues::TimeOfDay => :time_of_day
10
- }.freeze
11
-
12
- def localize(locale, object, format = :default, options = EMPTY_HASH)
13
- type = TYPES[object.class]
14
- return super unless type
15
-
16
- format_key = format.is_a?(Symbol) ? format : nil
17
-
18
- if format_key
19
- entry = I18n.t("#{type}.formats.#{format_key}", locale: locale, default: nil)
20
- raise I18n::MissingTranslationData.new(locale, "#{type}.formats.#{format_key}") unless entry
21
-
22
- format = entry
23
- end
24
-
25
- object.strftime(format)
26
- end
27
- end
28
- end
29
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DateValues
4
- module Rails
5
- class MonthDayType < ActiveModel::Type::Value
6
- def type
7
- :month_day
8
- end
9
-
10
- def cast(value)
11
- case value
12
- when MonthDay then value
13
- when String then MonthDay.parse(value)
14
- when nil then nil
15
- else raise ArgumentError, "can't cast #{value.class} to MonthDay"
16
- end
17
- end
18
-
19
- def serialize(value)
20
- value&.to_s
21
- end
22
-
23
- def deserialize(value)
24
- return nil if value.nil?
25
-
26
- MonthDay.parse(value)
27
- end
28
- end
29
- end
30
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DateValues
4
- module Rails
5
- class TimeOfDayType < ActiveModel::Type::Value
6
- def type
7
- :time_of_day
8
- end
9
-
10
- def cast(value)
11
- case value
12
- when TimeOfDay then value
13
- when Time then TimeOfDay.new(value.hour, value.min, value.sec)
14
- when String then TimeOfDay.parse(value)
15
- when nil then nil
16
- else raise ArgumentError, "can't cast #{value.class} to TimeOfDay"
17
- end
18
- end
19
-
20
- def serialize(value)
21
- value&.to_s
22
- end
23
-
24
- def deserialize(value)
25
- case value
26
- when nil then nil
27
- when Time then TimeOfDay.new(value.hour, value.min, value.sec)
28
- when String then TimeOfDay.parse(value)
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DateValues
4
- module Rails
5
- class YearMonthType < ActiveModel::Type::Value
6
- def type
7
- :year_month
8
- end
9
-
10
- def cast(value)
11
- case value
12
- when YearMonth then value
13
- when String then YearMonth.parse(value)
14
- when nil then nil
15
- else raise ArgumentError, "can't cast #{value.class} to YearMonth"
16
- end
17
- end
18
-
19
- def serialize(value)
20
- value&.to_s
21
- end
22
-
23
- def deserialize(value)
24
- return nil if value.nil?
25
-
26
- YearMonth.parse(value)
27
- end
28
- end
29
- end
30
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'date_values'
4
- require 'active_support'
5
- require 'active_model/type'
6
- require_relative 'rails/year_month_type'
7
- require_relative 'rails/month_day_type'
8
- require_relative 'rails/time_of_day_type'
9
- require_relative 'rails/i18n_backend'
10
-
11
- ActiveModel::Type.register(:year_month, DateValues::Rails::YearMonthType)
12
- ActiveModel::Type.register(:month_day, DateValues::Rails::MonthDayType)
13
- ActiveModel::Type.register(:time_of_day, DateValues::Rails::TimeOfDayType)
14
-
15
- ActiveSupport.on_load(:active_record) do
16
- ActiveRecord::Type.register(:year_month, DateValues::Rails::YearMonthType)
17
- ActiveRecord::Type.register(:month_day, DateValues::Rails::MonthDayType)
18
- ActiveRecord::Type.register(:time_of_day, DateValues::Rails::TimeOfDayType)
19
- end
20
-
21
- I18n::Backend::Base.prepend(DateValues::Rails::I18nBackend)
@@ -1,44 +0,0 @@
1
- module DateValues
2
- module Rails
3
- class YearMonthType < ActiveModel::Type::Value
4
- def type: () -> :year_month
5
-
6
- def cast: (YearMonth value) -> YearMonth
7
- | (String value) -> YearMonth
8
- | (nil value) -> nil
9
-
10
- def serialize: (YearMonth? value) -> String?
11
-
12
- def deserialize: (String value) -> YearMonth
13
- | (nil value) -> nil
14
- end
15
-
16
- class MonthDayType < ActiveModel::Type::Value
17
- def type: () -> :month_day
18
-
19
- def cast: (MonthDay value) -> MonthDay
20
- | (String value) -> MonthDay
21
- | (nil value) -> nil
22
-
23
- def serialize: (MonthDay? value) -> String?
24
-
25
- def deserialize: (String value) -> MonthDay
26
- | (nil value) -> nil
27
- end
28
-
29
- class TimeOfDayType < ActiveModel::Type::Value
30
- def type: () -> :time_of_day
31
-
32
- def cast: (TimeOfDay value) -> TimeOfDay
33
- | (Time value) -> TimeOfDay
34
- | (String value) -> TimeOfDay
35
- | (nil value) -> nil
36
-
37
- def serialize: (TimeOfDay? value) -> String?
38
-
39
- def deserialize: (Time value) -> TimeOfDay
40
- | (String value) -> TimeOfDay
41
- | (nil value) -> nil
42
- end
43
- end
44
- end