circa 0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +18 -0
- data/Rakefile +1 -0
- data/circa.gemspec +25 -0
- data/lib/circa.rb +27 -0
- data/lib/circa/date.rb +63 -0
- data/lib/circa/time.rb +51 -0
- data/lib/circa/util.rb +10 -0
- data/lib/circa/version.rb +5 -0
- data/spec/circa/date_spec.rb +61 -0
- data/spec/circa/time_spec.rb +54 -0
- data/spec/circa_spec.rb +24 -0
- metadata +144 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Robert Dallas Gray
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Circa
|
2
|
+
|
3
|
+
Use MySQL-style partial dates in Rails (and elsewhere).
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
$ date = circa('2001-01-00')
|
7
|
+
$ date.valid_parts
|
8
|
+
{ year: '2001', month: '01' }
|
9
|
+
$ date.to_date.to_s
|
10
|
+
'2001-01-01'
|
11
|
+
$ time = circa('2001-01-11 13:30:00')
|
12
|
+
$ time.valid_parts
|
13
|
+
{ year: '2001', month: '01', day: '11', hour: '13', minute: '30', second: '00' }
|
14
|
+
```
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
$ gem install circa
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/circa.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'circa/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'circa'
|
8
|
+
spec.version = Circa::VERSION
|
9
|
+
spec.authors = ['Robert Dallas Gray']
|
10
|
+
spec.email = ['mail@robertdallasgray.com']
|
11
|
+
spec.description = %q{Utilities for working with MySQL-style partial dates}
|
12
|
+
spec.summary = %q{Utilities for working with MySQL-style partial dates}
|
13
|
+
spec.homepage = ''
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.test_files = spec.files.grep(/^spec\//)
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
21
|
+
spec.add_development_dependency 'rake'
|
22
|
+
spec.add_development_dependency 'm', '~> 1.3.1'
|
23
|
+
spec.add_development_dependency 'guard', '>= 1.8'
|
24
|
+
spec.add_development_dependency 'guard-minitest'
|
25
|
+
end
|
data/lib/circa.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'circa/version'
|
2
|
+
require 'circa/date'
|
3
|
+
require 'circa/time'
|
4
|
+
|
5
|
+
module Circa
|
6
|
+
def circa(input_string)
|
7
|
+
if match_date(input_string)
|
8
|
+
Date.new(input_string)
|
9
|
+
elsif match_time(input_string)
|
10
|
+
Time.new(input_string)
|
11
|
+
else
|
12
|
+
raise ArgumentError, "Invalid input string: #{input_string}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def match_date(input_string)
|
19
|
+
input_string =~ Date::REGEX
|
20
|
+
end
|
21
|
+
|
22
|
+
def match_time(input_string)
|
23
|
+
date_re = Date::REGEX.source.sub(/\$$/, '')
|
24
|
+
time_re = Time::REGEX.source.sub(/^\^/, '')
|
25
|
+
input_string =~ Regexp.new("#{date_re}T|\s#{time_re}")
|
26
|
+
end
|
27
|
+
end
|
data/lib/circa/date.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require_relative 'util'
|
4
|
+
|
5
|
+
module Circa
|
6
|
+
class Date
|
7
|
+
include Util
|
8
|
+
REGEX = /^(\d{4})(?:-(0[0-9]|1[0-2])(?:-([0-2][0-9]|3[0-1])))$/
|
9
|
+
attr_reader :valid_parts
|
10
|
+
|
11
|
+
def initialize(date_string)
|
12
|
+
@year = '0000'
|
13
|
+
@month = '00'
|
14
|
+
@day = '00'
|
15
|
+
@valid_parts = {}
|
16
|
+
unless validate(date_string)
|
17
|
+
raise ArgumentError, "Invalid date: #{date_string}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
"#{@year}-#{@month}-#{@day}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_date
|
26
|
+
return nil if valid_parts.empty?
|
27
|
+
parts = [:year, :month, :day]
|
28
|
+
args = valid_parts_as_args(parts)
|
29
|
+
::Date.send(:new, *args)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def validate(date_string)
|
35
|
+
matches = REGEX.match(date_string)
|
36
|
+
return false if matches.nil?
|
37
|
+
set_year(matches) && set_month(matches) && set_day(matches)
|
38
|
+
end
|
39
|
+
|
40
|
+
def set_year(matches)
|
41
|
+
@year = matches[1]
|
42
|
+
set_dependent(@year, matches[2], :year)
|
43
|
+
end
|
44
|
+
|
45
|
+
def set_month(matches)
|
46
|
+
@month = matches[2]
|
47
|
+
set_dependent(@month, matches[3], :month)
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_dependent(a, b, name)
|
51
|
+
a.to_i > 0 ? @valid_parts[name] = a : b.to_i == 0
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_day(matches)
|
55
|
+
@day = matches[3]
|
56
|
+
if @day.to_i > 0
|
57
|
+
return false unless ::Date.strptime(matches[0]).to_s == matches[0]
|
58
|
+
@valid_parts[:day] = @day
|
59
|
+
end
|
60
|
+
true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/circa/time.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require_relative 'date'
|
4
|
+
require_relative 'util'
|
5
|
+
|
6
|
+
module Circa
|
7
|
+
class Time
|
8
|
+
include Util
|
9
|
+
REGEX = /^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])Z?$/
|
10
|
+
|
11
|
+
def initialize(time_string)
|
12
|
+
parts = time_string.split(/T|\s/)
|
13
|
+
@date = Date.new(parts[0])
|
14
|
+
@hour = '00'
|
15
|
+
@minute = '00'
|
16
|
+
@second = '00'
|
17
|
+
@valid_parts = {}
|
18
|
+
unless validate(parts[1])
|
19
|
+
raise ArgumentError, "Invalid time: #{time_string}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
"#{@date.to_s} #{@hour}:#{@minute}:#{@second}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def valid_parts
|
28
|
+
time_parts = { hour: @hour, minute: @minute, second: @second }
|
29
|
+
@date.valid_parts.merge(time_parts)
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_time
|
33
|
+
parts = [:year, :month, :day, :hour, :minute, :second]
|
34
|
+
args = valid_parts_as_args(parts)
|
35
|
+
::DateTime.send(:new, *args)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def validate(time_string)
|
41
|
+
time_string.chomp!('Z')
|
42
|
+
matches = REGEX.match(time_string)
|
43
|
+
set_time(matches) if matches
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_time(matches)
|
47
|
+
@hour, @minute, @second = matches[1..3]
|
48
|
+
[@hour, @minute, @second].join.to_i == 0 || @date.valid_parts[:day]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/circa/util.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'minitest/spec'
|
4
|
+
require_relative '../../lib/circa/date'
|
5
|
+
|
6
|
+
describe Circa::Date do
|
7
|
+
|
8
|
+
before do
|
9
|
+
@correct_date = '2001-11-11'
|
10
|
+
@zero_year = '0000-11-11'
|
11
|
+
@zero_month = '2001-00-11'
|
12
|
+
@incorrect_date = '2001-02-30'
|
13
|
+
@partial_date = '2001-11-00'
|
14
|
+
@zero_date = '0000-00-00'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should reject a date with a zero year and non-zero month' do
|
18
|
+
-> { Circa::Date.new(@zero_year) }.must_raise ArgumentError
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should reject a date with a zero month and non-zero day' do
|
22
|
+
-> { Circa::Date.new(@zero_month) }.must_raise ArgumentError
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should reject an incorrect date' do
|
26
|
+
-> { Circa::Date.new(@incorrect_date) }.must_raise ArgumentError
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should return a correct date string intact' do
|
30
|
+
Circa::Date.new(@correct_date).to_s.must_equal '2001-11-11'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should return a correct partial date string' do
|
34
|
+
Circa::Date.new(@partial_date).to_s.must_equal '2001-11-00'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should return valid date parts for a complete date' do
|
38
|
+
parts = Circa::Date.new(@correct_date).valid_parts
|
39
|
+
parts.must_equal({ year: '2001', month: '11', day: '11' })
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should return valid date parts for a partial date' do
|
43
|
+
parts = Circa::Date.new(@partial_date).valid_parts
|
44
|
+
parts.must_equal({ year: '2001', month: '11' })
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should return a correct date given a correct date string' do
|
48
|
+
date = Circa::Date.new(@correct_date).to_date
|
49
|
+
date.must_equal Date.new(2001, 11, 11)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should return a correct date given a partial date' do
|
53
|
+
date = Circa::Date.new(@partial_date).to_date
|
54
|
+
date.must_equal Date.new(2001, 11, 01)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should return nil on to_date given a zero date' do
|
58
|
+
date = Circa::Date.new(@zero_date).to_date
|
59
|
+
date.must_be_nil
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'minitest/spec'
|
4
|
+
require_relative '../../lib/circa/time'
|
5
|
+
|
6
|
+
describe Circa::Time do
|
7
|
+
|
8
|
+
before do
|
9
|
+
@correct_time = '2001-11-11 13:30:30'
|
10
|
+
@incorrect_time = '2001-11-11 24:30:30'
|
11
|
+
@zero_day = '2001-11-00 13:30:30'
|
12
|
+
@utc = '2001-11-11T13:30:30Z'
|
13
|
+
@partial_time = '2001-11-00 00:00:00'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should return a correct time string intact' do
|
17
|
+
Circa::Time.new(@correct_time).to_s.must_equal @correct_time
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should return a partial time string intact' do
|
21
|
+
Circa::Time.new(@partial_time).to_s.must_equal @partial_time
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should reject an incorrect time string' do
|
25
|
+
-> { Circa::Time.new(@incorrect_time) }.must_raise ArgumentError
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should reject a time with a zero day' do
|
29
|
+
-> { Circa::Time.new(@zero_day) }.must_raise ArgumentError
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should accept a UTC time string' do
|
33
|
+
Circa::Time.new(@utc).to_s.must_equal @correct_time
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should return valid parts' do
|
37
|
+
t = Circa::Time.new(@correct_time)
|
38
|
+
valid_parts = {
|
39
|
+
year: '2001', month: '11', day: '11',
|
40
|
+
hour: '13', minute: '30', second: '30'
|
41
|
+
}
|
42
|
+
t.valid_parts.must_equal valid_parts
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should return a correct datetime given a correct time' do
|
46
|
+
t = Circa::Time.new(@correct_time)
|
47
|
+
t.to_time.must_equal DateTime.new(2001, 11, 11, 13, 30, 30)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should return a correct datetime given a partial time' do
|
51
|
+
t = Circa::Time.new(@partial_time)
|
52
|
+
t.to_time.must_equal DateTime.new(2001, 11, 1, 0, 0, 0)
|
53
|
+
end
|
54
|
+
end
|
data/spec/circa_spec.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'minitest/spec'
|
4
|
+
require_relative '../lib/circa'
|
5
|
+
|
6
|
+
describe Circa do
|
7
|
+
|
8
|
+
before do
|
9
|
+
class Circafied
|
10
|
+
include Circa
|
11
|
+
end
|
12
|
+
@circafied = Circafied.new
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should return a new Circa::Date via a convenience method' do
|
16
|
+
d = @circafied.circa('2001-11-11')
|
17
|
+
d.must_be_instance_of Circa::Date
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should return a new Circa::Time via a convenience method' do
|
21
|
+
d = @circafied.circa('2001-11-11 13:30:30')
|
22
|
+
d.must_be_instance_of Circa::Time
|
23
|
+
end
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: circa
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Robert Dallas Gray
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: m
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.3.1
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.3.1
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: guard
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.8'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.8'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: guard-minitest
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Utilities for working with MySQL-style partial dates
|
95
|
+
email:
|
96
|
+
- mail@robertdallasgray.com
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- .gitignore
|
102
|
+
- Gemfile
|
103
|
+
- Guardfile
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- circa.gemspec
|
108
|
+
- lib/circa.rb
|
109
|
+
- lib/circa/date.rb
|
110
|
+
- lib/circa/time.rb
|
111
|
+
- lib/circa/util.rb
|
112
|
+
- lib/circa/version.rb
|
113
|
+
- spec/circa/date_spec.rb
|
114
|
+
- spec/circa/time_spec.rb
|
115
|
+
- spec/circa_spec.rb
|
116
|
+
homepage: ''
|
117
|
+
licenses:
|
118
|
+
- MIT
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
|
+
none: false
|
125
|
+
requirements:
|
126
|
+
- - ! '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
requirements: []
|
136
|
+
rubyforge_project:
|
137
|
+
rubygems_version: 1.8.23
|
138
|
+
signing_key:
|
139
|
+
specification_version: 3
|
140
|
+
summary: Utilities for working with MySQL-style partial dates
|
141
|
+
test_files:
|
142
|
+
- spec/circa/date_spec.rb
|
143
|
+
- spec/circa/time_spec.rb
|
144
|
+
- spec/circa_spec.rb
|