month 1.2.0 → 1.7.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
- SHA1:
3
- metadata.gz: 99d3a1f9ba6751770d9a06df16bd73ee776a8726
4
- data.tar.gz: 2939e754f6952365f4874ecf4cd6ae262975a723
2
+ SHA256:
3
+ metadata.gz: dc374de89e555a551ec3e4f67ca198a4fd0103d9bc256068b892f2405a049a6a
4
+ data.tar.gz: 8cc382ea4e97c8bbd0f234fcdb8808db495ad4ed487fbe8acb1ce7585c03d4d6
5
5
  SHA512:
6
- metadata.gz: c2e439bbb93bc6b10b0a7a0f0ead067c366660ecaa884c3a2eda73681f1ffa2032600b1964e6cc6fdb75b266f05d2065b7ab6f5a1e723de4179af7a4c82b8f11
7
- data.tar.gz: 38a4336b1e7c8ad7c258241379a174e4b9538dd76b826e0c1399efbf8e0db7fb00acf9080875f12383e9445b6665f30c3edc07d4fec4b2fb5837981e21a1e70e
6
+ metadata.gz: 11816342dee7af3574b80824283675823d703232fe39d3170e3f3ad424073584a0f4a95bae6b2ee1218b164a9d845245c2f8fe2ab63043554d2093c00abc7279
7
+ data.tar.gz: 0327fe3d9a9df8ea2957b13e28e1670585241187510a6f047883c2d0e02caea0cbb7ecb05b19f118f333ae46fd3b55d4774e654f72c785fe6cf5493142108fd1
@@ -1,4 +1,4 @@
1
- Copyright the authors and contributors. All rights reserved.
1
+ Copyright (c) 2014-2020 TIMCRAFT
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
data/README.md CHANGED
@@ -1,18 +1,24 @@
1
- month
2
- =====
1
+ # month
3
2
 
3
+ ![Gem Version](https://badge.fury.io/rb/month.svg)
4
+ ![Build Status](https://github.com/readysteady/month/workflows/Test/badge.svg)
4
5
 
5
- A little Ruby library for working with months.
6
6
 
7
+ Ruby gem for working with months.
7
8
 
8
- Installation
9
- ------------
9
+
10
+ ## Install
11
+
12
+ Using Bundler:
13
+
14
+ $ bundle add month
15
+
16
+ Using RubyGems:
10
17
 
11
18
  $ gem install month
12
19
 
13
20
 
14
- Feature tour
15
- ------------
21
+ ## Feature tour
16
22
 
17
23
  You can create a new Month object with a year and month number:
18
24
 
@@ -117,8 +123,7 @@ Month objects can be used in ranges.
117
123
  Month objects are comparable.
118
124
 
119
125
 
120
- Bonus Extras
121
- ------------
126
+ ## Bonus extras
122
127
 
123
128
  The Month::Methods module provides methods for constructing Month objects
124
129
  and Date objects in a manner that closely resembles written english:
@@ -135,8 +140,7 @@ It is not included globally by default; you can either include it within
135
140
  your own modules/classes or globally within your own application/script.
136
141
 
137
142
 
138
- History
139
- -------
143
+ ## Thanks
140
144
 
141
145
  This current implementation is an accidental rewrite of an older library/gem
142
146
  with the same name/purpose ([fhwang / month](https://github.com/fhwang/month)).
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'date'
2
3
 
3
4
  class Month
@@ -17,19 +18,25 @@ class Month
17
18
  }
18
19
 
19
20
  def initialize(year, number)
20
- unless NAMES.has_key?(number)
21
+ unless NAMES.key?(number)
21
22
  raise ArgumentError, 'invalid month number'
22
23
  end
23
24
 
24
25
  @year, @number = year, number
26
+
27
+ freeze
25
28
  end
26
29
 
27
30
  attr_reader :year, :number
28
31
 
32
+ alias_method :month, :number
33
+
29
34
  def to_s
30
35
  "#@year-#{@number.to_s.rjust(2, '0')}"
31
36
  end
32
37
 
38
+ alias_method :iso8601, :to_s
39
+
33
40
  def name
34
41
  NAMES.fetch(@number)
35
42
  end
@@ -49,6 +56,8 @@ class Month
49
56
  end
50
57
 
51
58
  def <=>(month)
59
+ return unless month.class == self.class
60
+
52
61
  if @year == month.year
53
62
  @number <=> month.number
54
63
  else
@@ -68,6 +77,18 @@ class Month
68
77
 
69
78
  alias_method :succ, :next
70
79
 
80
+ def >>(n)
81
+ self + n
82
+ end
83
+
84
+ alias_method :next_month, :>>
85
+
86
+ def <<(n)
87
+ self - n
88
+ end
89
+
90
+ alias_method :prev_month, :<<
91
+
71
92
  def step(limit, step = 1)
72
93
  raise ArgumentError if step.zero?
73
94
 
@@ -110,7 +131,7 @@ class Month
110
131
  if object.is_a?(Integer)
111
132
  self + (-object)
112
133
  else
113
- (year * 12 + @number) - (object.year * 12 + object.number)
134
+ 12 * (year - object.year) + (@number - object.number)
114
135
  end
115
136
  end
116
137
 
@@ -137,11 +158,17 @@ class Month
137
158
  end
138
159
  end
139
160
 
140
- def Month.parse(string)
141
- if string =~ /\A(\d{4})-(\d{2})\z/
142
- Month.new($1.to_i, $2.to_i)
143
- else
144
- raise ArgumentError, 'invalid month'
161
+ class Month
162
+ REGEXP = /\A(\d{4})-(\d{2})\z/
163
+
164
+ private_constant :REGEXP
165
+
166
+ def self.parse(string)
167
+ if string =~ REGEXP
168
+ Month.new($1.to_i, $2.to_i)
169
+ else
170
+ raise ArgumentError, 'invalid month'
171
+ end
145
172
  end
146
173
  end
147
174
 
@@ -156,6 +183,14 @@ def Month(object)
156
183
  end
157
184
  end
158
185
 
186
+ def Month.today
187
+ Month(Date.today)
188
+ end
189
+
190
+ def Month.now
191
+ Month(Time.now)
192
+ end
193
+
159
194
  class Month
160
195
  module Methods
161
196
  NAMES.each do |number, name|
@@ -0,0 +1,23 @@
1
+ require 'yaml'
2
+
3
+ class Month
4
+ def encode_with(coder)
5
+ coder.represent_scalar(nil, to_s)
6
+ end
7
+
8
+ module ScalarScannerPatch
9
+ REGEXP = /\A(\d{4})-(\d{2})\z/
10
+
11
+ def tokenize(string)
12
+ if !string.empty? && string.match(REGEXP)
13
+ return Month.new($1.to_i, $2.to_i)
14
+ end
15
+
16
+ super string
17
+ end
18
+
19
+ YAML::ScalarScanner.prepend(self)
20
+ end
21
+
22
+ private_constant :ScalarScannerPatch
23
+ end
@@ -1,16 +1,20 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'month'
3
- s.version = '1.2.0'
3
+ s.version = '1.7.0'
4
4
  s.license = 'MIT'
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ['Tim Craft']
7
7
  s.email = ['mail@timcraft.com']
8
- s.homepage = 'http://github.com/timcraft/month'
9
- s.description = 'A little Ruby library for working with months'
8
+ s.homepage = 'https://github.com/readysteady/month'
9
+ s.description = 'Ruby gem for working with months'
10
10
  s.summary = 'See description'
11
- s.files = Dir.glob('{lib,spec}/**/*') + %w(LICENSE.txt README.md month.gemspec)
11
+ s.files = Dir.glob('lib/**/*.rb') + %w(LICENSE.txt README.md month.gemspec)
12
12
  s.required_ruby_version = '>= 1.9.3'
13
- s.add_development_dependency('rake', '~> 10.0')
14
- s.add_development_dependency('minitest', '~> 5.0')
15
13
  s.require_path = 'lib'
14
+ s.metadata = {
15
+ 'homepage' => 'https://github.com/readysteady/month',
16
+ 'source_code_uri' => 'https://github.com/readysteady/month',
17
+ 'bug_tracker_uri' => 'https://github.com/readysteady/month/issues',
18
+ 'changelog_uri' => 'https://github.com/readysteady/month/blob/master/CHANGES.md'
19
+ }
16
20
  end
metadata CHANGED
@@ -1,44 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: month
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Craft
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-25 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: rake
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '10.0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '10.0'
27
- - !ruby/object:Gem::Dependency
28
- name: minitest
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '5.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '5.0'
41
- description: A little Ruby library for working with months
11
+ date: 2020-06-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ruby gem for working with months
42
14
  email:
43
15
  - mail@timcraft.com
44
16
  executables: []
@@ -48,12 +20,16 @@ files:
48
20
  - LICENSE.txt
49
21
  - README.md
50
22
  - lib/month.rb
23
+ - lib/month/yaml.rb
51
24
  - month.gemspec
52
- - spec/month_spec.rb
53
- homepage: http://github.com/timcraft/month
25
+ homepage: https://github.com/readysteady/month
54
26
  licenses:
55
27
  - MIT
56
- metadata: {}
28
+ metadata:
29
+ homepage: https://github.com/readysteady/month
30
+ source_code_uri: https://github.com/readysteady/month
31
+ bug_tracker_uri: https://github.com/readysteady/month/issues
32
+ changelog_uri: https://github.com/readysteady/month/blob/master/CHANGES.md
57
33
  post_install_message:
58
34
  rdoc_options: []
59
35
  require_paths:
@@ -69,8 +45,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
45
  - !ruby/object:Gem::Version
70
46
  version: '0'
71
47
  requirements: []
72
- rubyforge_project:
73
- rubygems_version: 2.2.2
48
+ rubygems_version: 3.1.2
74
49
  signing_key:
75
50
  specification_version: 4
76
51
  summary: See description
@@ -1,308 +0,0 @@
1
- require 'minitest/autorun'
2
-
3
- require_relative '../lib/month'
4
-
5
- describe 'Month' do
6
- it 'raises an exception when initialized with an invalid number' do
7
- proc { Month.new(2014, 0) }.must_raise(ArgumentError)
8
- proc { Month.new(2014, 100) }.must_raise(ArgumentError)
9
- end
10
-
11
- describe 'year method' do
12
- it 'returns the integer year of the month' do
13
- Month.new(2014, 1).year.must_equal(2014)
14
- end
15
- end
16
-
17
- describe 'number method' do
18
- it 'returns the integer number of the month' do
19
- Month.new(2014, 1).number.must_equal(1)
20
- end
21
- end
22
-
23
- describe 'to_s method' do
24
- it 'returns a string containing the year and zero padded number of the month' do
25
- Month.new(2014, 1).to_s.must_equal('2014-01')
26
- end
27
- end
28
-
29
- describe 'name method' do
30
- it 'returns the name of the month' do
31
- Month.new(2014, 1).name.must_equal(:January)
32
- end
33
- end
34
-
35
- describe 'january predicate method' do
36
- it 'returns true if the month is january' do
37
- Month.new(2014, 1).january?.must_equal(true)
38
- end
39
-
40
- it 'returns false otherwise' do
41
- Month.new(2014, 2).january?.must_equal(false)
42
- end
43
- end
44
-
45
- describe 'february predicate method' do
46
- it 'returns true if the month is february' do
47
- Month.new(2014, 2).february?.must_equal(true)
48
- end
49
-
50
- it 'returns false otherwise' do
51
- Month.new(2014, 1).february?.must_equal(false)
52
- end
53
- end
54
-
55
- it 'supports being used as a hash key' do
56
- hash, n = Hash.new(0), 10
57
-
58
- n.times { hash[Month.new(2014, 1)] += 1 }
59
-
60
- hash.count.must_equal(1)
61
- hash[Month.new(2014, 1)].must_equal(n)
62
- end
63
-
64
- it 'supports comparison between month objects' do
65
- Month.new(2014, 1).must_be_kind_of(Comparable)
66
-
67
- (Month.new(2014, 1) == Month.new(2014, 1)).must_equal(true)
68
- (Month.new(2014, 1) == Month.new(2014, 2)).must_equal(false)
69
-
70
- (Month.new(2014, 1) < Month.new(2014, 2)).must_equal(true)
71
- (Month.new(2014, 2) > Month.new(2014, 1)).must_equal(true)
72
- end
73
-
74
- it 'supports being used in a range' do
75
- range = Month.new(2014, 1) .. Month.new(2014, 4)
76
-
77
- range.map(&:number).must_equal([1, 2, 3, 4])
78
- end
79
-
80
- describe 'next method' do
81
- it 'returns a month object denoting the next month' do
82
- Month.new(2014, 1).next.must_equal(Month.new(2014, 2))
83
- Month.new(2014, 12).next.must_equal(Month.new(2015, 1))
84
- end
85
- end
86
-
87
- describe 'succ method' do
88
- it 'returns a month object denoting the next month' do
89
- Month.new(2014, 1).succ.must_equal(Month.new(2014, 2))
90
- Month.new(2014, 12).succ.must_equal(Month.new(2015, 1))
91
- end
92
- end
93
-
94
- describe 'step method' do
95
- it 'calls the block for every month until the given limit' do
96
- months = []
97
-
98
- Month.new(2014, 1).step(Month.new(2014, 3)) { |month| months << month }
99
-
100
- months.must_equal([Month.new(2014, 1), Month.new(2014, 2), Month.new(2014, 3)])
101
- end
102
-
103
- it 'returns an enumerator if no block was given' do
104
- months = Month.new(2014, 1).step(Month.new(2014, 3))
105
-
106
- months.must_be_instance_of(Enumerator)
107
-
108
- months.next.must_equal(Month.new(2014, 1))
109
- months.next.must_equal(Month.new(2014, 2))
110
- months.next.must_equal(Month.new(2014, 3))
111
- end
112
-
113
- it 'raises an exception when the given step argument is zero' do
114
- proc { Month.new(2014, 1).step(Month.new(2014, 3), 0) }.must_raise(ArgumentError)
115
- end
116
-
117
- it 'increases by the given number of months if the step argument is positive' do
118
- months = []
119
-
120
- Month.new(2014, 1).step(Month.new(2014, 3), 2) { |month| months << month }
121
-
122
- months.must_equal([Month.new(2014, 1), Month.new(2014, 3)])
123
- end
124
-
125
- it 'decreases by the given number of months if the step argument is negative' do
126
- months = []
127
-
128
- Month.new(2014, 3).step(Month.new(2014, 1), -1) { |month| months << month }
129
-
130
- months.must_equal([Month.new(2014, 3), Month.new(2014, 2), Month.new(2014, 1)])
131
- end
132
- end
133
-
134
- describe 'upto method' do
135
- it 'calls the block for every month until the given limit' do
136
- months = []
137
-
138
- Month.new(2014, 1).upto(Month.new(2014, 3)) { |month| months << month }
139
-
140
- months.must_equal([Month.new(2014, 1), Month.new(2014, 2), Month.new(2014, 3)])
141
- end
142
-
143
- it 'returns an enumerator if no block was given' do
144
- months = Month.new(2014, 1).upto(Month.new(2014, 3))
145
-
146
- months.must_be_instance_of(Enumerator)
147
-
148
- months.next.must_equal(Month.new(2014, 1))
149
- months.next.must_equal(Month.new(2014, 2))
150
- months.next.must_equal(Month.new(2014, 3))
151
- end
152
- end
153
-
154
- describe 'downto method' do
155
- it 'calls the block for every month until the given limit' do
156
- months = []
157
-
158
- Month.new(2014, 3).downto(Month.new(2014, 1)) { |month| months << month }
159
-
160
- months.must_equal([Month.new(2014, 3), Month.new(2014, 2), Month.new(2014, 1)])
161
- end
162
-
163
- it 'returns an enumerator if no block was given' do
164
- months = Month.new(2014, 3).downto(Month.new(2014, 1))
165
-
166
- months.must_be_instance_of(Enumerator)
167
-
168
- months.next.must_equal(Month.new(2014, 3))
169
- months.next.must_equal(Month.new(2014, 2))
170
- months.next.must_equal(Month.new(2014, 1))
171
- end
172
- end
173
-
174
- describe 'addition' do
175
- it 'returns a month object denoting the given number of months after self' do
176
- (Month.new(2014, 1) + 1).must_equal(Month.new(2014, 2))
177
- (Month.new(2014, 1) + 12).must_equal(Month.new(2015, 1))
178
- (Month.new(2014, 1) + 18).must_equal(Month.new(2015, 7))
179
- (Month.new(2013, 11) + 1).must_equal(Month.new(2013, 12))
180
- (Month.new(2013, 11) + 2).must_equal(Month.new(2014, 1))
181
- end
182
- end
183
-
184
- describe 'subtraction' do
185
- it 'returns a month object denoting the given number of months before self' do
186
- (Month.new(2014, 2) - 1).must_equal(Month.new(2014, 1))
187
- (Month.new(2014, 1) - 1).must_equal(Month.new(2013, 12))
188
- (Month.new(2014, 1) - 12).must_equal(Month.new(2013, 1))
189
- (Month.new(2014, 1) - 18).must_equal(Month.new(2012, 7))
190
- (Month.new(2013, 12) - 1).must_equal(Month.new(2013, 11))
191
- (Month.new(2014, 1) - 2).must_equal(Month.new(2013, 11))
192
- end
193
-
194
- it 'returns the number of months between the given month and self' do
195
- (Month.new(2014, 3) - Month.new(2014, 1)).must_equal(2)
196
- (Month.new(2015, 1) - Month.new(2014, 1)).must_equal(12)
197
- (Month.new(2077, 4) - Month.new(2070, 4)).must_equal(84)
198
- end
199
- end
200
-
201
- describe 'include predicate method' do
202
- it 'returns true if the month includes the given date' do
203
- Month.new(2014, 1).include?(Date.new(2014, 1, 1)).must_equal(true)
204
- end
205
-
206
- it 'returns false otherwise' do
207
- Month.new(2014, 1).include?(Date.new(2014, 2, 1)).must_equal(false)
208
- end
209
- end
210
-
211
- describe 'case equals method' do
212
- it 'returns true if the month includes the given date' do
213
- (Month.new(2014, 1) === Date.new(2014, 1, 1)).must_equal(true)
214
- end
215
-
216
- it 'returns false otherwise' do
217
- (Month.new(2014, 1) === Date.new(2014, 2, 1)).must_equal(false)
218
- end
219
- end
220
-
221
- describe 'start_date method' do
222
- it 'returns a date object denoting the first day of the month' do
223
- Month.new(2014, 1).start_date.must_equal(Date.new(2014, 1, 1))
224
- end
225
- end
226
-
227
- describe 'end_date method' do
228
- it 'returns a date object denoting the last day of the month' do
229
- Month.new(2014, 1).end_date.must_equal(Date.new(2014, 1, 31))
230
- end
231
- end
232
-
233
- describe 'dates method' do
234
- it 'returns the range of dates in the month' do
235
- dates = Month.new(2014, 1).dates
236
- dates.must_be_instance_of(Range)
237
- dates.count.must_equal(31)
238
- dates.all? { |date| Date === date }.must_equal(true)
239
- dates.first.must_equal(Date.new(2014, 1, 1))
240
- dates.last.must_equal(Date.new(2014, 1, 31))
241
- end
242
- end
243
-
244
- describe 'length method' do
245
- it 'returns the integer number of days in the month' do
246
- Month.new(2014, 1).length.must_equal(31)
247
- Month.new(2014, 2).length.must_equal(28)
248
- end
249
- end
250
- end
251
-
252
- describe 'Month parse method' do
253
- it 'returns the month corresponding to the given string representation' do
254
- Month.parse('2014-01').must_equal(Month.new(2014, 1))
255
- end
256
-
257
- it 'raises an exception if the format of the string is not as expected' do
258
- proc { Month.parse('January 2014') }.must_raise(ArgumentError)
259
- end
260
- end
261
-
262
- describe 'Month method' do
263
- it 'returns the month of the given date object' do
264
- Month(Date.new(2014, 1, 1)).must_equal(Month.new(2014, 1))
265
- end
266
-
267
- it 'returns the month of the given time object' do
268
- Month(Time.at(1234567890)).must_equal(Month.new(2009, 2))
269
- end
270
-
271
- it 'returns the month of the given datetime object' do
272
- Month(DateTime.parse('2001-02-03T04:05:06+07:00')).must_equal(Month.new(2001, 2))
273
- end
274
-
275
- it 'returns the month of the given integer unix timestamp' do
276
- Month(1234567890).must_equal(Month.new(2009, 2))
277
- end
278
-
279
- it 'idempotently returns the given month' do
280
- month = Month.new(2014, 1)
281
-
282
- Month(month).object_id.must_equal(month.object_id)
283
- end
284
- end
285
-
286
- describe 'A method defined in Month::Methods' do
287
- include Month::Methods
288
-
289
- it 'returns a month object denoting that month in the given year' do
290
- month = January 2014
291
- month.must_equal(Month.new(2014, 1))
292
-
293
- month = February 2014
294
- month.must_equal(Month.new(2014, 2))
295
- end
296
-
297
- it 'returns a date object when given two arguments' do
298
- date = January 31, 2014
299
- date.must_equal(Date.new(2014, 1, 31))
300
-
301
- date = February 28, 2014
302
- date.must_equal(Date.new(2014, 2, 28))
303
- end
304
-
305
- it 'raises an exception if given too many arguments' do
306
- proc { January 1, 2, 3 }.must_raise(ArgumentError)
307
- end
308
- end