stamp 0.0.3 → 0.1.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.
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - ree
5
+ - rbx
6
+ - rbx-2.0
7
+ - jruby
8
+ - ruby-head
9
+ - 1.8.6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stamp (0.0.2)
4
+ stamp (0.1.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
@@ -1,8 +1,10 @@
1
+ @stamp
1
2
  Feature: Stamping a date
2
3
  In order to format dates in a more programmer-friendly way
3
4
  the stamp method
4
5
  formats a date given a human-readable example.
5
6
 
7
+ @date
6
8
  Scenario Outline: Formatting dates by example
7
9
  Given the date October 9, 2011
8
10
  When I stamp the example "<example>"
@@ -33,15 +35,24 @@ Feature: Stamping a date
33
35
  | 1999-12-31 | 2011-10-09 |
34
36
  | DOB: 12-31-1999 | DOB: 10-09-2011 |
35
37
 
36
- @wip
37
- Scenario Outline: Examples that aren't supported quite yet
38
- Given the date October 9, 2011
38
+ @time
39
+ Scenario Outline: Formatting times by example
40
+ Given the time October 9, 2011 at 13:31:27
39
41
  When I stamp the example "<example>"
40
42
  Then I produce "<output>"
43
+ And I like turtles
41
44
 
42
45
  Examples:
43
- | example | output |
44
- | | |
46
+ | example | output |
47
+ | 8:59 am | 1:31 pm |
48
+ | 8:59am | 1:31pm |
49
+ | 08:59 AM | 01:31 PM |
50
+ | 08:59 PM | 01:31 PM |
51
+ | 23:59 | 13:31 |
52
+ | 8:59:59 am | 1:31:27 pm |
53
+ | 08:59:59 AM | 01:31:27 PM |
54
+ | 08:59:59 PM | 01:31:27 PM |
55
+ | 23:59:59 | 13:31:27 |
45
56
 
46
57
  Scenario: strftime directives just get passed through
47
58
  Given the date December 21, 2012
@@ -52,3 +63,16 @@ Feature: Stamping a date
52
63
  Given the date December 9, 2011
53
64
  When I stamp the example "Just some plain old text."
54
65
  Then I produce "Just some plain old text."
66
+
67
+
68
+ @wip
69
+ Scenario Outline: Examples that aren't supported yet
70
+ Given the date October 9, 2011
71
+ When I stamp the example "<example>"
72
+ Then I produce "<output>"
73
+
74
+ Examples:
75
+ | example | output |
76
+ | 8 am | 1 pm |
77
+ | 8am | 1pm |
78
+ | 8AM | 1PM |
@@ -1,13 +1,24 @@
1
+ module StampStepHelpers
2
+ def month(month_name)
3
+ month = Date::MONTHNAMES.index(month_name) || Date::ABBR_MONTHNAMES.index(month_name)
4
+ assert (1..12).include?(month), "Invalid month: #{month_name}"
5
+ return month
6
+ end
7
+ end
8
+ World(StampStepHelpers)
9
+
1
10
  Given /^the date (\w+) (\d+), (\d{4})$/ do |month_name, day, year|
2
- month = Date::MONTHNAMES.index(month_name) || Date::ABBR_MONTHNAMES.index(month_name)
3
- assert (1..12).include?(month), "Invalid month: #{month_name}"
4
- @date = Date.new(year.to_i, month, day.to_i)
11
+ @target = Date.new(year.to_i, month(month_name), day.to_i)
12
+ end
13
+
14
+ Given /^the time (\w+) (\d+), (\d+) at (\d{2}):(\d{2}):(\d{2})$/ do |month_name, day, year, hours, minutes, seconds|
15
+ @target = Time.new(year.to_i, month(month_name), day.to_i, hours.to_i, minutes.to_i, seconds.to_i)
5
16
  end
6
17
 
7
18
  When /^I stamp the example "([^"]*)"$/ do |example|
8
- @formatted_date = @date.stamp(example)
19
+ @stamped = @target.stamp(example)
9
20
  end
10
21
 
11
22
  Then /^I produce "([^"]*)"$/ do |expected|
12
- assert_equal expected, @formatted_date
23
+ assert_equal expected.strip, @stamped.strip
13
24
  end
data/lib/stamp.rb CHANGED
@@ -1,17 +1,14 @@
1
1
  require "stamp/version"
2
2
  require "date"
3
+ require "time"
3
4
 
4
5
  module Stamp
5
6
  def self.included(klass)
6
7
  klass.class_eval do
7
- # extend ClassMethods
8
8
  include InstanceMethods
9
9
  end
10
10
  end
11
11
 
12
- # module ClassMethods
13
- # end
14
-
15
12
  module InstanceMethods
16
13
 
17
14
  MONTHNAMES_REGEXP = /(#{Date::MONTHNAMES.compact.join('|')})/i
@@ -23,39 +20,98 @@ module Stamp
23
20
  TWO_DIGIT_REGEXP = /\d{2}/
24
21
  FOUR_DIGIT_REGEXP = /\d{4}/
25
22
 
26
- # DATE_DELIMITER_REGEXP = /(\/|\-)/ # forward slash or dash
23
+ TIME_REGEXP = /(\d{1,2})(:)(\d{2})(\s*)(:)?(\d{2})?(\s*)?([ap]m)?/i
27
24
 
28
- # OBVIOUS_MINUTES = 32..59
29
- # OBVIOUS_HOURS
30
- # OBVIOUS_SECONDS
25
+ MERIDIAN_LOWER_REGEXP = /(a|p)m/
26
+ MERIDIAN_UPPER_REGEXP = /(A|P)M/
31
27
 
28
+ # Disambiguate based on value
32
29
  OBVIOUS_YEARS = 60..99
33
30
  OBVIOUS_MONTHS = 12
34
31
  OBVIOUS_DAYS = 28..31
32
+ OBVIOUS_24_HOUR = 13..23
33
+
34
+ TWO_DIGIT_DATE_SUCCESSION = {
35
+ '%m' => '%d',
36
+ '%b' => '%d',
37
+ '%B' => '%d',
38
+ '%d' => '%y',
39
+ '%e' => '%y'
40
+ }
41
+
42
+ TWO_DIGIT_TIME_SUCCESSION = {
43
+ '%H' => '%M',
44
+ '%I' => '%M',
45
+ '%l' => '%M',
46
+ '%M' => '%S'
47
+ }
48
+
35
49
 
36
50
  def stamp(example)
37
- strftime(strftime_directives(example))
51
+ strftime(strftime_format(example))
38
52
  end
39
53
 
40
- def strftime_directives(example)
41
- directives = []
42
- previous_directive = nil
43
54
 
44
- terms = example.split(/\b/)
55
+ private
56
+
57
+ # Transforms the given string with example dates/times to a format string
58
+ # suitable for strftime.
59
+ def strftime_format(example)
60
+ # extract any substrings that look like times, like "23:59" or "8:37 am"
61
+ before, time_example, after = example.partition(TIME_REGEXP)
45
62
 
46
- terms.each_with_index do |term, index|
47
- directive = strftime_directive(term, previous_directive)
48
- directives << (directive || term)
63
+ # transform any date tokens to strftime directives
64
+ words = strftime_directives(before.split(/\b/)) do |token, previous_directive|
65
+ strftime_date_directive(token, previous_directive)
66
+ end
49
67
 
68
+ # transform the example time string to strftime directives
69
+ unless time_example.empty?
70
+ time_parts = time_example.scan(TIME_REGEXP).first
71
+ words += strftime_directives(time_parts) do |token, previous_directive|
72
+ strftime_time_directive(token, previous_directive)
73
+ end
74
+ end
75
+
76
+ # recursively process any remaining text
77
+ words << strftime_format(after) unless after.empty?
78
+ words.join
79
+ end
80
+
81
+ # Transforms tokens that look like date/time parts to strftime directives.
82
+ def strftime_directives(tokens)
83
+ previous_directive = nil
84
+ tokens.map do |token|
85
+ directive = yield(token, previous_directive)
50
86
  previous_directive = directive unless directive.nil?
87
+ directive || token
51
88
  end
89
+ end
90
+
91
+ def strftime_time_directive(token, previous_directive)
92
+ case token
93
+ when MERIDIAN_LOWER_REGEXP
94
+ '%P'
95
+
96
+ when MERIDIAN_UPPER_REGEXP
97
+ '%p'
98
+
99
+ when TWO_DIGIT_REGEXP
100
+ TWO_DIGIT_TIME_SUCCESSION[previous_directive] ||
101
+ case token.to_i
102
+ when OBVIOUS_24_HOUR
103
+ '%H' # 24-hour clock
104
+ else
105
+ '%I' # 12-hour clock with leading zero
106
+ end
52
107
 
53
- directives.join
108
+ when ONE_DIGIT_REGEXP
109
+ '%l' # hour without leading zero
110
+ end
54
111
  end
55
- private :strftime_directives
56
112
 
57
- def strftime_directive(term, previous_directive=nil)
58
- case term
113
+ def strftime_date_directive(token, previous_directive)
114
+ case token
59
115
  when MONTHNAMES_REGEXP
60
116
  '%B'
61
117
 
@@ -73,7 +129,7 @@ module Stamp
73
129
 
74
130
  when TWO_DIGIT_REGEXP
75
131
  # try to discern obvious intent based on the example value
76
- case term.to_i
132
+ case token.to_i
77
133
  when OBVIOUS_YEARS
78
134
  '%y'
79
135
  when OBVIOUS_MONTHS
@@ -83,22 +139,16 @@ module Stamp
83
139
  else
84
140
  # the intent isn't obvious based on the example value, so try to
85
141
  # disambiguate based on context
86
- case previous_directive
87
- when '%m', '%b', '%B' # a month
88
- '%d' # day with leading zero
89
- when '%d', '%e' # a day
90
- '%y' # two-digit year
91
- else
92
- '%m' # month
93
- end
142
+ TWO_DIGIT_DATE_SUCCESSION[previous_directive] || '%m'
94
143
  end
95
144
 
96
145
  when ONE_DIGIT_REGEXP
97
146
  '%e' # day without leading zero
98
147
  end
99
148
  end
100
- private :strftime_directive
101
149
  end
102
150
  end
103
151
 
104
- Date.send(:include, ::Stamp)
152
+
153
+ Date.send(:include, ::Stamp)
154
+ Time.send(:include, ::Stamp)
data/lib/stamp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Stamp
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
+ - 1
7
8
  - 0
8
- - 3
9
- version: 0.0.3
9
+ version: 0.1.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jeremy Weiskotten
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-06-30 00:00:00 -04:00
17
+ date: 2011-07-05 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -55,6 +55,7 @@ extra_rdoc_files: []
55
55
  files:
56
56
  - .gitignore
57
57
  - .rvmrc
58
+ - .travis.yml
58
59
  - Gemfile
59
60
  - Gemfile.lock
60
61
  - LICENSE.txt