carbon_date 0.1.1 → 0.1.2

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
  SHA1:
3
- metadata.gz: 15ca7832b179451649cfe8cbf847532875ba167b
4
- data.tar.gz: 8131707b3b7d297ead922c9cde6ef1caf0186d17
3
+ metadata.gz: c60c02d57fde03497403333831fb9c699374bd78
4
+ data.tar.gz: 1a65132b4dff055a69503b2c58138482872d11f7
5
5
  SHA512:
6
- metadata.gz: 3fef630e9f37ff2d13d51f97d84e6cfe07d8d841ce645f22adc6686650d4250ab377f7eccddae5d5ad5e66b1e19db6aa858a0048944331eac0ceef372b408b96
7
- data.tar.gz: 3117e099d4ae329636dfe80f9d7c0f203657be0112bd4584d30993076d8f870855ad9744267e7f8b1c3d476e4c5b75dca8d8d30fac3d041c5a1846f68bc2fa83
6
+ metadata.gz: ea46f3105ebf35dbf78b2dc9bfc66ec6e94e35a07fbe28f29db8b65a46e8e186efe02fc0a6d8855424b37dc279605181c2091c8c5ffbb984f4247f510fa55b3f
7
+ data.tar.gz: 02b78be58c703446b079467a916ab7d7f5d154805708e22cdde7ff17c66cd53e2dd853df87017f91db7499690614139278d6f193b2f331145dda9d13a0d719cd
data/.gitignore CHANGED
@@ -8,4 +8,5 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  /test/html_reports/
11
- /*.gem
11
+ /*.gem
12
+ /.coveralls.yml
data/README.md CHANGED
@@ -1,4 +1,6 @@
1
1
  [![Gem Version](http://img.shields.io/gem/v/carbon_date.svg?style=flat-square)](https://rubygems.org/gems/carbon_date)
2
+ [![Coverage Status](https://coveralls.io/repos/github/bradleymarques/carbon_date/badge.svg?branch=master)](https://coveralls.io/github/bradleymarques/carbon_date?branch=master)
3
+ [![Inline docs](http://inch-ci.org/github/bradleymarques/carbon_date.svg?branch=master)](http://inch-ci.org/github/bradleymarques/carbon_date)
2
4
  [![License](http://img.shields.io/:license-mit-blue.svg?style=flat-square)](http://bradleymarques.mit-license.org)
3
5
 
4
6
  # CarbonDate
data/carbon_date.gemspec CHANGED
@@ -36,6 +36,8 @@ Gem::Specification.new do |spec|
36
36
  spec.add_development_dependency 'pry', '~> 0.10.3', '>= 0.10.3'
37
37
  spec.add_development_dependency 'rdoc', '~> 4.2.2', '>= 4.2.2'
38
38
  spec.add_development_dependency 'mocha', '~> 1.1.0', '>= 1.1.0'
39
+ spec.add_development_dependency 'coveralls', '~> 0.8.13', '>= 0.8.13'
40
+
39
41
 
40
42
  spec.add_dependency 'activesupport', '~> 4.2.6', '>= 4.2.6'
41
43
  end
data/lib/carbon_date.rb CHANGED
@@ -3,6 +3,13 @@ require 'carbon_date/formatter'
3
3
  require 'carbon_date/standard_formatter'
4
4
  require 'carbon_date/version'
5
5
 
6
+ ##
7
+ # Provides a custom implmentation of +Date+ with precision.
8
+ #
9
+ # Classes:
10
+ # - +Date+
11
+ # - +Formatter+
12
+ # - +StandardFormatter+ < +Formatter+
6
13
  module CarbonDate
7
14
 
8
15
 
@@ -4,39 +4,68 @@ require 'carbon_date/standard_formatter'
4
4
  module CarbonDate
5
5
 
6
6
  ##
7
- # A date with a precision
7
+ # Models a date with a precision.
8
+ # The conventions of the Gregorian Calendar are used to model dates.
8
9
  class Date
9
10
 
11
+ # The class-wide Formatter to use to turn CarbonDate::Dates into human-readable strings
10
12
  @formatter = CarbonDate::StandardFormatter.new
11
13
 
12
14
  class << self
15
+ # Used to get and set the CarbonDate::Date.formatter
13
16
  attr_accessor :formatter
14
17
  end
15
18
 
16
19
  ##
17
20
  # The precisions available
18
- #
19
- # TODO: Consider refactoring into a simple array of symbols, since level could be replaced by the index in the array
20
- PRECISION = [
21
- {symbol: :second, level: 14},
22
- {symbol: :minute, level: 13},
23
- {symbol: :hour, level: 12},
24
- {symbol: :day, level: 11},
25
- {symbol: :month, level: 10},
26
- {symbol: :year, level: 9,},
27
- {symbol: :decade, level: 8,},
28
- {symbol: :century, level: 7,},
29
- {symbol: :millennium, level: 6,},
30
- {symbol: :ten_thousand_years, level: 5,},
31
- {symbol: :hundred_thousand_years, level: 4},
32
- {symbol: :million_years, level: 3},
33
- {symbol: :ten_million_years, level: 2},
34
- {symbol: :hundred_million_years, level: 1},
35
- {symbol: :billion_years, level: 0}
21
+ PRECISION =
22
+ [
23
+ :billion_years,
24
+ :hundred_million_years,
25
+ :ten_million_years,
26
+ :million_years,
27
+ :hundred_thousand_years,
28
+ :ten_thousand_years,
29
+ :millennium,
30
+ :century,
31
+ :decade,
32
+ :year,
33
+ :month,
34
+ :day,
35
+ :hour,
36
+ :minute,
37
+ :second
36
38
  ]
37
39
 
38
- attr_reader :precision, :year, :month, :day, :hour, :minute, :second
39
-
40
+ # The date's precision
41
+ attr_reader :precision
42
+ # The date's year. Cannot be 0 as there is no 0 year in the Gregorian Calendar.
43
+ attr_reader :year
44
+ # The date's month in range (1..12)
45
+ attr_reader :month
46
+ # The date's day counting from 1
47
+ attr_reader :day
48
+ # The date's hour in range (0..23)
49
+ attr_reader :hour
50
+ # The date's minute in range (0..59)
51
+ attr_reader :minute
52
+ # The date's second in range (0..59)
53
+ attr_reader :second
54
+
55
+ # Creates a new CarbonDate::Date
56
+ #
57
+ # Params:
58
+ # +year+ - The date's year, as an integer
59
+ # +month+ - The date's month, as an integer
60
+ # +day+ - The date's day, as an integer
61
+ # +hour+ - The date's hour, as an integer
62
+ # +minute+ - The date's minute, as an integer
63
+ # +second+ - The date's second, as an integer
64
+ # +:precision+ - The date's precision, as a symbol. For avaiable options, see CarbonDate::Date::PRECISION
65
+ # Raises:
66
+ # +ArgumentError+ if validations fail
67
+ # Returns:
68
+ # +CarbonDate::Date+ object
40
69
  def initialize(year = 1970, month = 1, day = 1, hour = 0, minute = 0, second = 0, precision: :second)
41
70
  month = 1 if month == 0
42
71
  day = 1 if day == 0
@@ -47,97 +76,76 @@ module CarbonDate
47
76
  self.second = second
48
77
  end
49
78
 
50
- ##
51
79
  # Sets the precision
52
- #
53
- # Raises ArgumentError if invalid symbol
80
+ # Raises +ArgumentError+ if invalid symbol
54
81
  def precision=(value)
55
- p = PRECISION.find { |x| x[:symbol] == value }
56
- raise ArgumentError.new "Invalid precision #{value}" unless p
57
- @precision = p
82
+ raise ArgumentError.new "Invalid precision #{value}" unless PRECISION.include? value
83
+ @precision = value
58
84
  end
59
85
 
60
- ##
61
- # An atomic function to set the date component.
62
- #
63
- # Raises ArgumentError if invalid date
86
+ # An atomic function to set the date component (year, month and day)
87
+ # Raises +ArgumentError+ if invalid date
64
88
  def set_date(year, month, day)
65
-
66
- raise ArgumentError.new("Invalid date #{year}-#{month}-#{day}") unless (1..12).include? month
67
- raise ArgumentError.new("Invalid date #{year}-#{month}-#{day}") if (year.nil? || year == 0)
68
-
89
+ raise invalid_date if (year.nil? || year == 0 || !((1..12).include? month))
69
90
  begin
70
91
  ::Date.new(year, month, day)
71
92
  rescue ArgumentError
72
- raise ArgumentError.new("Invalid date #{year}-#{month}-#{day}")
93
+ raise invalid_date
73
94
  end
74
-
75
95
  @year = year.to_i
76
96
  @month = month
77
97
  @day = day
78
-
79
98
  end
80
99
 
81
- ##
82
100
  # Sets the year. Calls set_date() to ensure atomicity.
83
101
  def year=(value)
84
102
  set_date(value, @month, @day)
85
103
  end
86
104
 
87
- ##
88
105
  # Sets the month. Calls set_date() to ensure atomicity.
89
- #
90
- # Raises ArgumentError if:
106
+ # Raises +ArgumentError+ if:
91
107
  # - value is not in (1..12)
92
108
  def month=(value)
93
109
  set_date(@year, value, @day)
94
110
  end
95
111
 
96
- ##
97
- # Sets the month. Calls set_date() to ensure atomicity.
98
- #
99
- # Raises ArgumentError if:
112
+ # Sets the day. Calls set_date() to ensure atomicity.
113
+ # Raises +ArgumentError+ if:
100
114
  # - value is not in (1..12)
101
115
  def day=(value)
102
116
  set_date(@year, @month, value)
103
117
  end
104
118
 
105
- ##
106
119
  # Sets the hour with validation
107
- #
108
- # Raises ArgumentError unless in the range (0..23)
120
+ # Raises +ArgumentError+ unless in the range (0..23)
109
121
  def hour=(value)
110
122
  raise ArgumentError.new "Invalid hour #{value}" unless (0..23).include? value
111
123
  @hour = value
112
124
  end
113
125
 
114
- ##
115
126
  # Sets the minute with validation
116
- #
117
- # Raises ArgumentError unless in the range (0..59)
127
+ # Raises +ArgumentError+ unless in the range (0..59)
118
128
  def minute=(value)
119
129
  raise ArgumentError.new "Invalid minute #{value}" unless (0..59).include? value
120
130
  @minute = value
121
131
  end
122
132
 
123
- ##
124
133
  # Sets the second with validation
125
- #
126
- # Raises ArgumentError unless in the range (0..59)
134
+ # Raises +ArgumentError+ unless in the range (0..59)
127
135
  def second=(value)
128
136
  raise ArgumentError.new "Invalid second #{value}" unless (0..59).include? value
129
137
  @second = value
130
138
  end
131
139
 
132
- ##
133
140
  # Converts from an iso8601 datetime format, with precision
134
- #
135
141
  # Dates like these are found on Wikidata (https://www.wikidata.org)
136
- #
142
+ # Params:
137
143
  # +string+ -> the iso8601 datetime in the form +1989-03-23T23:11:08Z
138
144
  # +precision_level+ -> an integer between 0 and 14 (see CarbonDate::Date::PRECISION)
145
+ # Returns:
146
+ # +CarbonDate::Date+ object
139
147
  def self.iso8601(string, precision_level)
140
- p = PRECISION.find { |x| x[:level] == precision_level}
148
+ p = PRECISION[precision_level]
141
149
  raise ArgumentError.new("Invalid precision level #{precision_level}") unless p
142
150
  # If there is an initial '-' symbol on the year, it needs to be treateded differenty than the other '-'.
143
151
  # Example: -0500-01-01 is the 1st January 500 BCE
@@ -149,39 +157,57 @@ module CarbonDate
149
157
  end
150
158
  d = string.split('T').map { |x| x.split(/[-:]/) }.flatten.map(&:to_i)
151
159
  year = bce ? -d[0] : d[0]
152
- CarbonDate::Date.new(year, d[1], d[2], d[3], d[4], d[5], precision: p[:symbol])
160
+ CarbonDate::Date.new(year, d[1], d[2], d[3], d[4], d[5], precision: p)
153
161
  end
154
162
 
155
- ##
156
- # Prints a human-readable version of the date, using a Formatter
163
+ # Prints a human-readable version of the date, using CarbonDate::Date.formatter
157
164
  def to_s
158
165
  CarbonDate::Date.formatter.date_to_string(self)
159
166
  end
160
167
 
161
- ##
162
168
  # Convert to a standard Ruby Date object
169
+ # Returns:
170
+ # +::Date+ object
163
171
  def to_date
164
172
  ::Date.new(@year, @month, @day)
165
173
  end
166
174
 
167
- ##
168
175
  # Convert into a standard Ruby DateTime object
176
+ # Returns:
177
+ # +::DateTime+ object
169
178
  def to_datetime
170
179
  ::DateTime.new(@year, @month, @day, @hour, @minute, @second)
171
180
  end
172
181
 
182
+ # Test equality of two CarbonDate::Dates
183
+ # For equality, the two dates have to have the same:
184
+ # - precision
185
+ # - year
186
+ # - month
187
+ # - day
188
+ # - hour
189
+ # - minute
190
+ # - second
173
191
  def ==(another_date)
174
192
  return false if self.precision != another_date.precision
175
193
  self.to_datetime == another_date.to_datetime
176
194
  end
177
195
 
196
+ # Tests if this CarbonDate::Date is in the past relative to the other CarbonDate::Date
197
+ # Defers to DateTime#<=
178
198
  def <=(another_date)
179
199
  self.to_datetime <= another_date.to_datetime
180
200
  end
181
201
 
202
+ # Tests if this CarbonDate::Date is in the future relative to the other CarbonDate::Date
203
+ # Defers to DateTime#>=
182
204
  def >=(another_date)
183
205
  self.to_datetime >= another_date.to_datetime
184
206
  end
185
207
 
208
+ def invalid_date
209
+ ArgumentError.new("Invalid date #{year}-#{month}-#{day}")
210
+ end
211
+
186
212
  end
187
213
  end
@@ -1,28 +1,46 @@
1
1
  module CarbonDate
2
2
 
3
3
  ##
4
- # Responsible for formatting a CarbonDate::Date to a human-readable string
4
+ # Responsible for formatting a CarbonDate::Date as a human-readable string. Used when CarbonDate::Date#to_s is called.
5
+ #
6
+ # You can extend Formatter to create your own custom output for dates.
7
+ # class MyCustomFormatter < CarbonDate::Formatter
8
+ # def year(date)
9
+ # # ...
10
+ # end
11
+ # # ...
12
+ # end
13
+ #
14
+ # Then, to use your custom formatter, simply do:
15
+ # CarbonDate::Date.formatter = MyCustomFormatter.new
16
+ # All subsequent dates will be formatted using your custom formatter.
17
+ # Implementations of Formatter need to override all of the following methods:
18
+ # - +billion_years(date)+
19
+ # - +hundred_million_years(date)+
20
+ # - +ten_million_years(date)+
21
+ # - +million_years(date)+
22
+ # - +hundred_thousand_years(date)+
23
+ # - +ten_thousand_years(date)+
24
+ # - +millennium(date)+
25
+ # - +century(date)+
26
+ # - +decade(date)+
27
+ # - +year(date)+
28
+ # - +month(date)+
29
+ # - +day(date)+
30
+ # - +hour(date)+
31
+ # - +minute(date)+
32
+ # - +second(date)+
33
+ # All of the above methods take a CarbonDate::Date as a parameter.
5
34
  class Formatter
6
35
 
36
+ ##
37
+ # Formats a CarbonDate::Date object as a human-readable string
7
38
  def date_to_string(date)
8
- precision = date.precision.fetch(:symbol, nil)
9
- case precision
10
- when :billion_years then billion_years(date)
11
- when :hundred_million_years then hundred_million_years(date)
12
- when :ten_million_years then ten_million_years(date)
13
- when :million_years then million_years(date)
14
- when :hundred_thousand_years then hundred_thousand_years(date)
15
- when :ten_thousand_years then ten_thousand_years(date)
16
- when :millennium then millennium(date)
17
- when :century then century(date)
18
- when :decade then decade(date)
19
- when :year then year(date)
20
- when :month then month(date)
21
- when :day then day(date)
22
- when :hour then hour(date)
23
- when :minute then minute(date)
24
- when :second then second(date)
25
- else raise StandardError.new("Unrecognized precision: #{precision}")
39
+ precision = date.precision
40
+ if CarbonDate::Date::PRECISION.include? precision # Call me paranoid: whitelist the available functions
41
+ public_send(precision, date)
42
+ else
43
+ raise StandardError.new("Unrecognized precision: #{precision}")
26
44
  end
27
45
  end
28
46
  end
@@ -6,86 +6,135 @@ module CarbonDate
6
6
  # The default formatter for CarbonDate::Date
7
7
  class StandardFormatter < Formatter
8
8
 
9
- ##
10
9
  # Suffix to use for Before Common Era dates (quite often BCE or BC)
11
10
  BCE_SUFFIX = 'BCE'
12
11
 
12
+ # Collection of strings denoting month names for this Formatter
13
13
  MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
14
14
 
15
- private
16
-
15
+ # Formats a CarbonDate::Date with year precision as a string
16
+ # Returns:
17
+ # A human-readable string representing the Date
17
18
  def year(date)
18
19
  y = date.year.abs.to_s
19
20
  return [y, BCE_SUFFIX].join(' ') if (date.year <= -1)
20
21
  y
21
22
  end
22
23
 
24
+ # Formats a CarbonDate::Date with month precision as a string
25
+ # Returns:
26
+ # A human-readable string representing the Date
23
27
  def month(date)
24
28
  [MONTHS[date.month - 1], year(date)].join(', ')
25
29
  end
26
30
 
31
+ # Formats a CarbonDate::Date with day precision as a string
32
+ # Returns:
33
+ # A human-readable string representing the Date
27
34
  def day(date)
28
35
  [date.day.ordinalize.to_s, month(date)].join(' ')
29
36
  end
30
37
 
38
+ # Formats a CarbonDate::Date with hour precision as a string
39
+ # Returns:
40
+ # A human-readable string representing the Date
31
41
  def hour(date)
32
42
  h = date.minute >= 30 ? date.hour + 1 : date.hour
33
43
  time = [pad(h.to_s), '00'].join(':')
34
44
  [time, day(date)].join(' ')
35
45
  end
36
46
 
47
+ # Formats a CarbonDate::Date with minute precision as a string
48
+ # Returns:
49
+ # A human-readable string representing the Date
37
50
  def minute(date)
38
51
  time = [pad(date.hour.to_s), pad(date.minute.to_s)].join(':')
39
52
  [time, day(date)].join(' ')
40
53
  end
41
54
 
55
+ # Formats a CarbonDate::Date with second precision as a string
56
+ # Returns:
57
+ # A human-readable string representing the Date
42
58
  def second(date)
43
59
  time = [pad(date.hour.to_s), pad(date.minute.to_s), pad(date.second.to_s)].join(':')
44
60
  [time, day(date)].join(' ')
45
61
  end
46
62
 
63
+ # Formats a CarbonDate::Date with decade precision
64
+ # Returns:
65
+ # A human-readable string representing the Date
47
66
  def decade(date)
48
67
  d = ((date.year.abs.to_i / 10) * 10).to_s + 's'
49
68
  return [d, BCE_SUFFIX].join(' ') if (date.year <= -1)
50
69
  d
51
70
  end
52
71
 
72
+ # Formats a CarbonDate::Date with century precision
73
+ # Returns:
74
+ # A human-readable string representing the Date
53
75
  def century(date)
54
76
  c = ((date.year.abs.to_i / 100) + 1).ordinalize + ' century'
55
77
  return [c, BCE_SUFFIX].join(' ') if (date.year <= -1)
56
78
  c
57
79
  end
58
80
 
81
+ # Formats a CarbonDate::Date with millennium precision
82
+ # Returns:
83
+ # A human-readable string representing the Date
59
84
  def millennium(date)
60
85
  m = ((date.year.abs.to_i / 1000) + 1).ordinalize + ' millennium'
61
86
  return [m, BCE_SUFFIX].join(' ') if (date.year <= -1)
62
87
  m
63
88
  end
64
89
 
90
+ # Formats a CarbonDate::Date with ten_thousand_years precision
91
+ # Returns:
92
+ # A human-readable string representing the Date
65
93
  def ten_thousand_years(date)
66
94
  coarse_precision(date.year, 10e3.to_i)
67
95
  end
68
96
 
97
+ # Formats a CarbonDate::Date with hundred_thousand_years precision
98
+ # Returns:
99
+ # A human-readable string representing the Date
69
100
  def hundred_thousand_years(date)
70
101
  coarse_precision(date.year, 100e3.to_i)
71
102
  end
72
103
 
104
+ # Formats a CarbonDate::Date with million_years precision
105
+ # Returns:
106
+ # A human-readable string representing the Date
73
107
  def million_years(date)
74
108
  coarse_precision(date.year, 1e6.to_i)
75
109
  end
76
110
 
111
+ # Formats a CarbonDate::Date with ten_million_years precision
112
+ # Returns:
113
+ # A human-readable string representing the Date
77
114
  def ten_million_years(date)
78
115
  coarse_precision(date.year, 10e6.to_i)
79
116
  end
80
117
 
118
+ # Formats a CarbonDate::Date with hundred_million_years precision
119
+ # Returns:
120
+ # A human-readable string representing the Date
81
121
  def hundred_million_years(date)
82
122
  coarse_precision(date.year, 100e6.to_i)
83
123
  end
84
124
 
125
+ # Formats a CarbonDate::Date with billion_years precision
126
+ # Returns:
127
+ # A human-readable string representing the Date
85
128
  def billion_years(date)
86
129
  coarse_precision(date.year, 1e9.to_i)
87
130
  end
88
131
 
132
+ # A helper function used to format dates that have less than millenium precision
133
+ # Params:
134
+ # +date_year+ The year component of the CarbonDate::Date being formatted
135
+ # +interval+ The precision in years
136
+ # Returns:
137
+ # A human-readable string representing the Date
89
138
  def coarse_precision(date_year, interval)
90
139
 
91
140
  date_year = date_year.to_i
@@ -102,10 +151,26 @@ module CarbonDate
102
151
  nil
103
152
  end
104
153
 
154
+ # Converts an integer number into a human-readable string with thousands delimiters.
155
+ # Example:
156
+ # number_with_delimiter(1234567890, ',')
157
+ # => 1,234,567,890
158
+ # Params:
159
+ # +n+ the number to be delimited. Will be converted to an integer
160
+ # +delim+ the string to be used as the thousands delimiter. Defaults to ','
105
161
  def number_with_delimiter(n, delim = ',')
106
162
  n.to_i.to_s.reverse.chars.each_slice(3).map(&:join).join(delim).reverse
107
163
  end
108
164
 
165
+ # Pad a string with '0' to ensure it has two characters.
166
+ # If a string of 2 or more characters is used as parameter, will not alter the string.
167
+ # Example:
168
+ # pad('1')
169
+ # => "01"
170
+ # Params:
171
+ # +s+ The string to pad.
172
+ # Returns:
173
+ # A string of at least 2 characters
109
174
  def pad(s)
110
175
  s.rjust(2, '0')
111
176
  end
@@ -1,3 +1,3 @@
1
1
  module CarbonDate
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carbon_date
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bradley Marques
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-06-12 00:00:00.000000000 Z
11
+ date: 2016-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -184,6 +184,26 @@ dependencies:
184
184
  - - ">="
185
185
  - !ruby/object:Gem::Version
186
186
  version: 1.1.0
187
+ - !ruby/object:Gem::Dependency
188
+ name: coveralls
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: 0.8.13
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ version: 0.8.13
197
+ type: :development
198
+ prerelease: false
199
+ version_requirements: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - "~>"
202
+ - !ruby/object:Gem::Version
203
+ version: 0.8.13
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: 0.8.13
187
207
  - !ruby/object:Gem::Dependency
188
208
  name: activesupport
189
209
  requirement: !ruby/object:Gem::Requirement