edtf 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -6,3 +6,6 @@ group :debug do
6
6
  gem 'ruby-debug', :platforms => [:mri_18, :jruby]
7
7
  gem 'rbx-trepanning', :platforms => [:rbx]
8
8
  end
9
+
10
+ # active_support requires this
11
+ gem 'i18n'
data/edtf.gemspec CHANGED
@@ -15,6 +15,8 @@ Gem::Specification.new do |s|
15
15
  s.description = 'An Extended Date/Time Format (EDTF) Parser for Ruby.'
16
16
  s.license = 'FreeBSD'
17
17
 
18
+ s.add_runtime_dependency('activesupport', ['~>3.0'])
19
+
18
20
  s.add_development_dependency('rake', ['~>0.9'])
19
21
  s.add_development_dependency('racc', ['~>1.4'])
20
22
  s.add_development_dependency('cucumber', ['~>1.0'])
@@ -3,7 +3,7 @@ Feature: EDTF parser parses date strings
3
3
  In order to use dates in EDTF
4
4
  As a user of edtf-ruby
5
5
  I want to parse date strings formatted in EDTF
6
-
6
+
7
7
  Scenario Outline: EDTF parses a date string
8
8
  When I parse the string "<string>"
9
9
  Then the year should be "<year>"
@@ -4,16 +4,15 @@ Feature: EDTF parses ISO 8601 interval strings
4
4
 
5
5
  Scenario Outline: parse intervals
6
6
  When I parse the string "<string>"
7
- Then the interval should start at "<from>"
8
- And the interval should end at "<to>"
7
+ Then the interval should include the date "<date>"
9
8
 
10
9
  @004 @level0
11
10
  Scenarios: specification intervals
12
- | string | from | to |
13
- | 1964/2008 | 1964-01-01 | 2008-01-01 |
14
- | 2004-06/2006-08 | 2004-06-01 | 2006-08-01 |
15
- | 2004-01-01/2004-01-02 | 2004-01-01 | 2004-01-02 |
16
- | 2004-02-01/2005-02-08 | 2004-02-01 | 2005-02-08 |
17
- | 2004-02-01/2005-02 | 2004-02-01 | 2005-02-01 |
18
- | 2004-02-01/2005 | 2004-02-01 | 2005-01-01 |
19
- | 2005/2006-02 | 2005-01-01 | 2006-02-01 |
11
+ | string | date |
12
+ | 1964/2008 | 1964-01-01 |
13
+ | 2004-06/2006-08 | 2006-08-31 |
14
+ | 2004-01-01/2004-01-02 | 2004-01-01 |
15
+ | 2004-02-01/2005-02-08 | 2005-02-08 |
16
+ | 2004-02-01/2005-02 | 2004-12-01 |
17
+ | 2004-02-01/2005 | 2005-12-31 |
18
+ | 2005/2006-02 | 2005-01-01 |
@@ -0,0 +1,68 @@
1
+ Feature: Print Date/Time objects as Level 1 EDTF strings
2
+ As a Ruby programmer
3
+ I want to convert Date/Time objects to EDTF strings
4
+
5
+ Scenario: Convert simple dates
6
+ Given the date "2004-08-12"
7
+ When I convert the date
8
+ Then the EDTF string should be "2004-08-12"
9
+
10
+ Scenario: Convert simple dates with precision
11
+ Given the date "1980-08-24" with precision set to "day"
12
+ When I convert the date
13
+ Then the EDTF string should be "1980-08-24"
14
+ Given the date "1980-08-24" with precision set to "month"
15
+ When I convert the date
16
+ Then the EDTF string should be "1980-08"
17
+ Given the date "1980-08-24" with precision set to "year"
18
+ When I convert the date
19
+ Then the EDTF string should be "1980"
20
+
21
+ Scenario: Date Roundtrips
22
+ When I parse the string "2001-02-03"
23
+ When I convert the date
24
+ Then the EDTF string should be "2001-02-03"
25
+ When I parse the string "2001-02"
26
+ When I convert the date
27
+ Then the EDTF string should be "2001-02"
28
+ When I parse the string "2001"
29
+ When I convert the date
30
+ Then the EDTF string should be "2001"
31
+ When I parse the string "-9909"
32
+ When I convert the date
33
+ Then the EDTF string should be "-9909"
34
+ When I parse the string "0000"
35
+ When I convert the date
36
+ Then the EDTF string should be "0000"
37
+
38
+ Scenario: DateTime Roundtrips
39
+ When I parse the string "2001-02-03T09:30:01"
40
+ When I convert the date
41
+ Then the EDTF string should be "2001-02-03T09:30:01+00:00"
42
+ When I parse the string "2004-01-01T10:10:10Z"
43
+ When I convert the date
44
+ Then the EDTF string should be "2004-01-01T10:10:10+00:00"
45
+ When I parse the string "2004-01-01T10:10:10+05:00"
46
+ When I convert the date
47
+ Then the EDTF string should be "2004-01-01T10:10:10+05:00"
48
+
49
+ Scenario: Interval Roundtrips
50
+ When I parse the string "1964/2008"
51
+ When I convert the date
52
+ Then the EDTF string should be "1964/2008"
53
+ When I parse the string "2004-06/2006-08"
54
+ When I convert the date
55
+ Then the EDTF string should be "2004-06/2006-08"
56
+ When I parse the string "2004-02-01/2005-02-08"
57
+ When I convert the date
58
+ Then the EDTF string should be "2004-02-01/2005-02-08"
59
+ When I parse the string "2004-02-01/2005-02"
60
+ When I convert the date
61
+ Then the EDTF string should be "2004-02-01/2005-02"
62
+ When I parse the string "2004-02-01/2005"
63
+ When I convert the date
64
+ Then the EDTF string should be "2004-02-01/2005"
65
+ When I parse the string "2005/2006-02"
66
+ When I convert the date
67
+ Then the EDTF string should be "2005/2006-02"
68
+
@@ -0,0 +1,8 @@
1
+ Feature: Print Date/Time objects as Level 2 EDTF strings
2
+ As a Ruby programmer
3
+ I want to convert Date/Time objects to EDTF strings
4
+
5
+ Scenario: Uncertain or approximate dates
6
+ When I parse the string "2001?"
7
+ When I convert the date
8
+ Then the EDTF string should be "2001?"
@@ -1,80 +1,98 @@
1
+ Given /^the date "([^"]*)"(?: with precision set to "([^"]*)")?$/ do |date, precision|
2
+ @date = Date.parse(date)
3
+ @date.precision = precision unless precision.nil?
4
+ end
5
+
6
+ When /^I convert the date$/ do
7
+ @string = @date.edtf
8
+ end
9
+
10
+ Then /^the EDTF String should be "([^"]*)"$/i do |edtf|
11
+ @string.should == edtf
12
+ end
13
+
1
14
  When /^I parse the string "([^"]*)"$/ do |string|
2
- @edtf = EDTF.parse(string)
15
+ @date = EDTF.parse(string)
3
16
  end
4
17
 
5
18
  Then /^the year should be "([^"]*)"$/ do |year|
6
- @edtf.year.should == year.to_i
19
+ @date.year.should == year.to_i
7
20
  end
8
21
 
9
22
  Then /^the month should be "([^"]*)"$/ do |month|
10
- @edtf.month.should == month.to_i
23
+ @date.month.should == month.to_i
11
24
  end
12
25
 
13
26
  Then /^the day should be "([^"]*)"$/ do |day|
14
- @edtf.day.should == day.to_i
27
+ @date.day.should == day.to_i
15
28
  end
16
29
 
17
30
  Then /^the hours should be "([^"]*)"$/ do |hours|
18
- @edtf.hour.should == hours.to_i
31
+ @date.hour.should == hours.to_i
19
32
  end
20
33
 
21
34
  Then /^the year should be "([^"]*)" \(UTC\)$/ do |year|
22
- @edtf.to_time.utc.year.should == year.to_i
35
+ @date.to_time.utc.year.should == year.to_i
23
36
  end
24
37
 
25
38
  Then /^the month should be "([^"]*)" \(UTC\)$/ do |month|
26
- @edtf.to_time.utc.month.should == month.to_i
39
+ @date.to_time.utc.month.should == month.to_i
27
40
  end
28
41
 
29
42
  Then /^the day should be "([^"]*)" \(UTC\)$/ do |day|
30
- @edtf.to_time.utc.day.should == day.to_i
43
+ @date.to_time.utc.day.should == day.to_i
31
44
  end
32
45
 
33
46
  Then /^the hours should be "([^"]*)" \(UTC\)$/ do |hours|
34
- @edtf.to_time.utc.hour.should == hours.to_i
47
+ @date.to_time.utc.hour.should == hours.to_i
35
48
  end
36
49
 
37
50
 
38
51
  Then /^the minutes should be "([^"]*)"$/ do |minutes|
39
- @edtf.min.should == minutes.to_i
52
+ @date.min.should == minutes.to_i
40
53
  end
41
54
 
42
55
  Then /^the seconds should be "([^"]*)"$/ do |seconds|
43
- @edtf.sec.should == seconds.to_i
56
+ @date.sec.should == seconds.to_i
44
57
  end
45
58
 
46
59
  Then /^the duration should range from "([^"]*)" to "([^"]*)"$/ do |from,to|
47
- [@edtf.begin.year.to_s, @edtf.end.year.to_s].should == [from,to]
60
+ [@date.begin.year.to_s, @date.end.year.to_s].should == [from,to]
48
61
  end
49
62
 
50
63
  Then /^the interval should start at "([^"]*)"$/ do |date|
51
- @edtf.begin.to_s.should == date
64
+ @date.begin.to_s.should == date
52
65
  end
53
66
 
54
67
  Then /^the interval should end at "([^"]*)"$/ do |date|
55
- @edtf.end.to_s.should == date
68
+ @date.end.to_s.should == date
69
+ end
70
+
71
+ Then /^the interval should include the date "([^"]*)"$/ do |date|
72
+ @date.should include(Date.parse(date))
56
73
  end
57
74
 
75
+
58
76
  Then /^the date should be uncertain\? "([^"]*)"$/ do |arg1|
59
- @edtf.uncertain?.should == !!(arg1 =~ /y(es)?/i)
77
+ @date.uncertain?.should == !!(arg1 =~ /y(es)?/i)
60
78
  end
61
79
 
62
80
  Then /^the year should be uncertain\? "([^"]*)"$/ do |arg1|
63
- @edtf.uncertain?(:year).should == !!(arg1 =~ /y(es)?/i)
81
+ @date.uncertain?(:year).should == !!(arg1 =~ /y(es)?/i)
64
82
  end
65
83
 
66
84
  Then /^the month should be uncertain\? "([^"]*)"$/ do |arg1|
67
- @edtf.uncertain?(:month).should == !!(arg1 =~ /y(es)?/i)
85
+ @date.uncertain?(:month).should == !!(arg1 =~ /y(es)?/i)
68
86
  end
69
87
 
70
88
  Then /^the day should be uncertain\? "([^"]*)"$/ do |arg1|
71
- @edtf.uncertain?(:day).should == !!(arg1 =~ /y(es)?/i)
89
+ @date.uncertain?(:day).should == !!(arg1 =~ /y(es)?/i)
72
90
  end
73
91
 
74
92
  Then /^the date should be approximate\? "([^"]*)"$/ do |arg1|
75
- @edtf.approximate?.should == !!(arg1 =~ /y(es)?/i)
93
+ @date.approximate?.should == !!(arg1 =~ /y(es)?/i)
76
94
  end
77
95
 
78
96
  Then /^the unspecified string code be "([^"]*)"$/ do |arg1|
79
- @edtf.unspecified.to_s.should == arg1
97
+ @date.unspecified.to_s.should == arg1
80
98
  end
data/lib/edtf.rb CHANGED
@@ -33,13 +33,21 @@ autoload :Rational, 'rational'
33
33
 
34
34
  require 'forwardable'
35
35
 
36
+ require 'active_support/core_ext/date/calculations'
37
+ require 'active_support/core_ext/date_time/calculations'
38
+ require 'active_support/core_ext/time/calculations'
39
+
40
+
41
+ require 'active_support/core_ext/date/conversions'
42
+
36
43
  require 'edtf/compatibility'
37
44
 
38
45
  require 'edtf/version'
39
46
  require 'edtf/uncertainty'
40
- require 'edtf/seasons'
41
47
  require 'edtf/date'
42
48
  require 'edtf/date_time'
49
+ require 'edtf/epoch'
50
+ require 'edtf/season'
43
51
  require 'edtf/interval'
44
52
  require 'edtf/parser'
45
53
  require 'edtf/extensions'
@@ -1,11 +1,10 @@
1
1
 
2
- unless DateTime.respond_to?(:to_time)
3
- require 'time'
4
-
5
- class DateTime
6
- def to_time
7
- Time.parse(to_s)
8
- end
9
- end
10
-
11
- end
2
+ # unless DateTime.respond_to?(:to_time)
3
+ # require 'time'
4
+ #
5
+ # class DateTime
6
+ # def to_time
7
+ # Time.parse(to_s)
8
+ # end
9
+ # end
10
+ # end
data/lib/edtf/date.rb CHANGED
@@ -1,140 +1,187 @@
1
- module EDTF
1
+ class Date
2
2
 
3
3
  PRECISIONS = [:year, :month, :day].freeze
4
+ FORMATS = %w{ %04d %02d %02d }.freeze
4
5
 
5
- module ExtendedDate
6
-
7
- extend Forwardable
8
-
9
- include Seasons
10
-
11
- attr_accessor :calendar
12
-
13
- attr_reader :precision
14
-
15
- def precision=(precision)
16
- raise ArgumentError, "invalid precision #{precision.inspect}" unless PRECISIONS.include?(precision.to_sym)
17
- @precision = precision.to_sym
18
- update_precision_filter[-1]
19
- end
20
-
21
- def self.included(base)
22
- base.extend(ClassMethods)
6
+ EXTENDED_ATTRIBUTES = %w{ calendar precision uncertain approximate
7
+ unspecified }.map(&:intern).freeze
8
+
9
+ extend Forwardable
10
+
11
+ class << self
12
+ def edtf(input, options = {})
13
+ ::EDTF::Parser.new(options).parse(input)
23
14
  end
24
-
25
- def uncertain
26
- @uncertain ||= Uncertainty.new
15
+ end
16
+
17
+ attr_accessor :calendar
18
+
19
+ PRECISIONS.each do |p|
20
+ define_method("#{p}_precision?") { @precision == p }
21
+ define_method("#{p}_precision!") { @precision = p }
22
+ end
23
+
24
+ def dup
25
+ d = super
26
+ d.uncertain = uncertain.dup
27
+ d.approximate = approximate.dup
28
+ d.unspecified = unspecified.dup
29
+ d
30
+ end
31
+
32
+ # Alias change method from Active Support.
33
+ alias original_change change
34
+
35
+ # Returns a new Date where one or more of the elements have been changed according to the +options+ parameter.
36
+ def change(options)
37
+ d = original_change(options)
38
+ EXTENDED_ATTRIBUTES.each do |attribute|
39
+ d.send("#{attribute}=", options[attribute] || send(attribute))
27
40
  end
41
+ d
42
+ end
43
+
44
+ # Returns this Date's precision.
45
+ def precision
46
+ @precision ||= :day
47
+ end
48
+
49
+ def precision=(precision)
50
+ precision = precision.intern
51
+ raise ArgumentError, "invalid precision #{precision.inspect}" unless PRECISIONS.include?(precision)
52
+ @precision = precision
53
+ update_precision_filter[-1]
54
+ end
55
+
56
+ def self.included(base)
57
+ base.extend(ClassMethods)
58
+ end
59
+
60
+ def uncertain
61
+ @uncertain ||= EDTF::Uncertainty.new
62
+ end
28
63
 
29
- def approximate
30
- @approximate ||= Uncertainty.new
31
- end
64
+ def approximate
65
+ @approximate ||= EDTF::Uncertainty.new
66
+ end
32
67
 
33
- def unspecified
34
- @unspecified ||= Unspecified.new
35
- end
36
-
37
- def_delegators :uncertain, :uncertain?, :certain?
68
+ def unspecified
69
+ @unspecified ||= EDTF::Unspecified.new
70
+ end
71
+
72
+ def_delegators :uncertain, :uncertain?, :certain?
38
73
 
39
- def certain!(*arguments)
40
- uncertain.certain!(*arguments)
41
- self
42
- end
43
-
44
- def uncertain!(*arguments)
45
- uncertain.uncertain!(*arguments)
46
- self
47
- end
74
+ def certain!(*arguments)
75
+ uncertain.certain!(*arguments)
76
+ self
77
+ end
78
+
79
+ def uncertain!(*arguments)
80
+ uncertain.uncertain!(*arguments)
81
+ self
82
+ end
48
83
 
49
- def approximate?(*arguments)
50
- approximate.uncertain?(*arguments)
51
- end
52
-
53
- alias approximately? approximate?
54
-
55
- def approximate!(*arguments)
56
- approximate.uncertain!(*arguments)
57
- self
58
- end
59
-
60
- alias approximately! approximate!
61
-
62
- def precise?(*arguments)
63
- !approximate?(*arguments)
64
- end
65
-
66
- alias precisely? precise?
84
+ def approximate?(*arguments)
85
+ approximate.uncertain?(*arguments)
86
+ end
87
+
88
+ alias approximately? approximate?
89
+
90
+ def approximate!(*arguments)
91
+ approximate.uncertain!(*arguments)
92
+ self
93
+ end
94
+
95
+ alias approximately! approximate!
96
+
97
+ def precise?(*arguments)
98
+ !approximate?(*arguments)
99
+ end
100
+
101
+ alias precisely? precise?
67
102
 
68
- def precise!(*arguments)
69
- approximate.certain!(*arguments)
70
- self
71
- end
103
+ def precise!(*arguments)
104
+ approximate.certain!(*arguments)
105
+ self
106
+ end
72
107
 
73
- alias precisely! precise!
74
-
75
- def_delegators :unspecified, :unspecified?, :specified?, :unsepcific?, :specific?
76
-
77
- def unspecified!(*arguments)
78
- unspecified.unspecified!(*arguments)
79
- self
80
- end
108
+ alias precisely! precise!
109
+
110
+ def_delegators :unspecified, :unspecified?, :specified?, :unsepcific?, :specific?
111
+
112
+ def unspecified!(*arguments)
113
+ unspecified.unspecified!(*arguments)
114
+ self
115
+ end
81
116
 
82
- alias unspecific! unspecified!
117
+ alias unspecific! unspecified!
83
118
 
84
- def specified!(*arguments)
85
- unspecified.specified!(*arguments)
86
- self
87
- end
119
+ def specified!(*arguments)
120
+ unspecified.specified!(*arguments)
121
+ self
122
+ end
88
123
 
89
- alias specific! specified!
90
-
91
- def to_edtf
92
- "TODO"
93
- end
124
+ alias specific! specified!
125
+
126
+ def season?; false; end
127
+
128
+ def season
129
+ Season.new(self)
130
+ end
131
+
132
+ def edtf
133
+ FORMATS.take(values.length).join('-') % values
134
+ end
94
135
 
95
- # TODO take precision into account
96
- def next
97
- super
98
- end
99
-
100
- def values
101
- precision_filter.map { |p| send(p) }
102
- end
103
-
104
- # Returns the same date with negated year
105
- def negate
106
- v = values
107
- y = -1 * v.shift
108
- self.class.new(y, *v) # TODO copy extended attributes
109
- end
110
-
111
- alias -@ negate
112
-
113
-
114
- private
115
-
116
- def precision_filter
117
- @precision_filter ||= update_precision_filter
118
- end
119
-
120
- def update_precision_filter
121
- case @precision
122
- when :year
123
- [:year]
124
- when :month
125
- [:year,:month]
126
- else
127
- [:year,:month,:day]
128
- end
129
- end
136
+ alias to_edtf edtf
137
+
138
+ def next
139
+ send("next_#{precision}")
140
+ end
141
+
142
+ # def succ
143
+ # end
130
144
 
131
-
132
- module ClassMethods
133
- def edtf(input, options = {})
134
- ::EDTF::Parser.new(options).parse(input)
135
- end
145
+ # def ==(other)
146
+ # end
147
+
148
+ # def <=>(other)
149
+ # end
150
+
151
+ # def ===(other)
152
+ # end
153
+
154
+ def values
155
+ precision_filter.map { |p| send(p) }
156
+ end
157
+
158
+ # Returns the same date with negated year
159
+ def negate
160
+ change(:year => year * -1)
161
+ end
162
+
163
+ alias -@ negate
164
+
165
+
166
+ private
167
+
168
+ def precision_filter
169
+ @precision_filter ||= update_precision_filter
170
+ end
171
+
172
+ def update_precision_filter
173
+ case @precision
174
+ when :year
175
+ [:year]
176
+ when :month
177
+ [:year,:month]
178
+ else
179
+ [:year,:month,:day]
136
180
  end
137
-
138
181
  end
182
+
183
+ protected
184
+
185
+ attr_writer :uncertain, :unspecified, :approximate
139
186
 
140
- end
187
+ end