repeatable 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 03a465c906b9b2d7fdff5ffc02f1d101f87d3ab8
4
- data.tar.gz: d29495e2f3820d482dc6a7e71c21623db1d8a8bf
3
+ metadata.gz: 49614dbb77808403fec7ce7b17f8e6b4c5c6ee99
4
+ data.tar.gz: 19759e4931d334759c54f6a80c9856fe92bc01e3
5
5
  SHA512:
6
- metadata.gz: 857276ebf76281f5aa7b2c71599417aeb1da1e7fc0f5bbda36806f5165b47eb92a10ede29e510351858eb0b32a3c5dbb2e82f485cacecf9e8547e2ec1605ec07
7
- data.tar.gz: 4f5cc44ae471c8bf0006c4570c09e829b803f44cb5661c3dc9fce721e1ed519ecc3b5373016b70d9ad6a2952c96b0fc75dfd2f51d27875fdc2ec555ee9d652fd
6
+ metadata.gz: 89a121c2ecf46fbb6cd89bf150a00dff53452fa2cbfddaf4bff89255455f7bab86aa09d50ea0e5a4d60de7306f70096657dfb2f63a59b2092aa2fe5bb9bb149c
7
+ data.tar.gz: f0c55a63c03e9055b40cc90183ad176eb75027411a71de000a4f95c0f57a6dd85b9ee98a4c581539475c9712fb08f4e59c13f765b3711abb9b2c5719ecf65416
data/CHANGELOG.md ADDED
@@ -0,0 +1,59 @@
1
+ ## CHANGELOG
2
+
3
+ ### Unreleased
4
+
5
+ [Commits](https://github.com/molawson/repeatable/compare/v0.4.0...master)
6
+
7
+ ### 0.4.0 (2015-06-29)
8
+
9
+ Features:
10
+
11
+ * Define equivalence `#==` for `Expression` and `Schedule` objects
12
+ * Define hash equality `#eql?` for `Expression::Date` objects
13
+ * Remove `ActiveSupport` dependency
14
+
15
+ [Commits](https://github.com/molawson/repeatable/compare/v0.3.0...v0.4.0)
16
+
17
+ ### 0.3.0 (2015-03-11)
18
+
19
+ Features:
20
+
21
+ * Ensure `end_date` on or after `start_date` for `Schedule#occurrences` ([@danott][])
22
+ * Consider any invalid argument to `Schedule.new` a `ParseError` ([@danott][])
23
+
24
+ [Commits](https://github.com/molawson/repeatable/compare/v0.2.1...v0.3.0)
25
+
26
+ ### 0.2.1 (2015-03-09)
27
+
28
+ Features:
29
+
30
+ * Add `ParseError` class for better error handling
31
+ * Extract `Parser` class from `Schedule`
32
+
33
+ Bugfixes:
34
+
35
+ * Enable `Schedule` to take a hash with string keys
36
+
37
+ [Commits](https://github.com/molawson/repeatable/compare/v0.2.0...v0.2.1)
38
+
39
+ ### 0.2.0 (2015-03-03)
40
+
41
+ Features:
42
+
43
+ * Add `Schedule#to_h` and `Expression#to_h` methods
44
+ * Enable building a `Schedule` from composed `Expression` objects
45
+
46
+ Bugfixes:
47
+
48
+ * Fix default case equality for `Expression::Base` to work with classes and instances
49
+
50
+ [Commits](https://github.com/molawson/repeatable/compare/v0.1.0...v0.2.0)
51
+
52
+ ### 0.1.0 (2015-02-23)
53
+
54
+ Initial Release
55
+
56
+ [Commits](https://github.com/molawson/repeatable/compare/531d40c...v0.1.0)
57
+
58
+
59
+ [@danott]: https://github.com/danott
data/README.md CHANGED
@@ -138,6 +138,29 @@ schedule.to_h
138
138
  # can be used to recreate an identical Schedule object at a later time
139
139
  ```
140
140
 
141
+ #### Equivalence
142
+
143
+ Both `Repeatable::Schedule` and all `Repeatable::Expression` classes have equivalence `#==` defined according to what's appropriate for each class, so regardless of the order of arguments passed to each, you can tell whether one object is equivalent to the other in terms of whether or not, when asked the same questions, you'd receive the same results from each.
144
+
145
+ ```ruby
146
+ Repeatable::Expression::DayInMonth.new(day: 1) == Repeatable::Expression::DayInMonth.new(day: 1)
147
+ # => true
148
+
149
+ first = Repeatable::Expression::DayInMonth.new(day: 1)
150
+ fifteenth = Repeatable::Expression::DayInMonth.new(day: 15)
151
+ first == fifteenth
152
+ # => false
153
+
154
+ union = Repeatable::Expression::Union.new(first, fifteenth)
155
+ another_union = Repeatable::Expression::Union.new(fifteenth, first)
156
+ union == another_union
157
+ # => true (order of Union and Intersection arguments doesn't their affect output)
158
+
159
+ Repeatable::Schedule.new(union) == Repeatable::Schedule.new(another_union)
160
+ # => true (their expressions are equivalent, so they'll produce the same results)
161
+
162
+ ```
163
+
141
164
  ## Development
142
165
 
143
166
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -23,6 +23,15 @@ module Repeatable
23
23
  "Don't use Expression::Base directly. Subclasses must implement `#to_h`"
24
24
  )
25
25
  end
26
+
27
+ private
28
+
29
+ def hash_key
30
+ self.class.name.split('::').last
31
+ .gsub(/(?<!\b)[A-Z]/) { "_#{Regexp.last_match[0]}" }
32
+ .downcase
33
+ .to_sym
34
+ end
26
35
  end
27
36
  end
28
37
  end
@@ -0,0 +1,26 @@
1
+ module Repeatable
2
+ module Expression
3
+ class Date < Base
4
+
5
+ def to_h
6
+ Hash[hash_key, attributes]
7
+ end
8
+
9
+ def ==(other)
10
+ other.is_a?(self.class) && attributes == other.attributes
11
+ end
12
+
13
+ alias eql? ==
14
+
15
+ def hash
16
+ [attributes.values, self.class.name].hash
17
+ end
18
+
19
+ protected
20
+
21
+ def attributes
22
+ Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] }]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,6 +1,6 @@
1
1
  module Repeatable
2
2
  module Expression
3
- class DayInMonth < Base
3
+ class DayInMonth < Date
4
4
  def initialize(day:)
5
5
  @day = day
6
6
  end
@@ -9,10 +9,6 @@ module Repeatable
9
9
  date.day == day
10
10
  end
11
11
 
12
- def to_h
13
- { day_in_month: { day: day } }
14
- end
15
-
16
12
  private
17
13
 
18
14
  attr_reader :day
@@ -1,6 +1,6 @@
1
1
  module Repeatable
2
2
  module Expression
3
- class RangeInYear < Base
3
+ class RangeInYear < Date
4
4
  def initialize(start_month:, end_month: start_month, start_day: 0, end_day: 0)
5
5
  @start_month = start_month
6
6
  @end_month = end_month
@@ -2,21 +2,25 @@ module Repeatable
2
2
  module Expression
3
3
  class Set < Base
4
4
  def initialize(*elements)
5
- @elements = elements.flatten
5
+ @elements = elements.flatten.uniq
6
6
  end
7
7
 
8
8
  def <<(element)
9
- elements << element
9
+ elements << element unless elements.include?(element)
10
10
  self
11
11
  end
12
12
 
13
13
  def to_h
14
- hash = {}
15
- hash[self.class.name.demodulize.underscore.to_sym] = elements.map(&:to_h)
16
- hash
14
+ Hash[hash_key, elements.map(&:to_h)]
17
15
  end
18
16
 
19
- private
17
+ def ==(other)
18
+ other.is_a?(self.class) &&
19
+ elements.size == other.elements.size &&
20
+ other.elements.all? { |e| elements.include?(e) }
21
+ end
22
+
23
+ protected
20
24
 
21
25
  attr_reader :elements
22
26
  end
@@ -1,6 +1,6 @@
1
1
  module Repeatable
2
2
  module Expression
3
- class Weekday < Base
3
+ class Weekday < Date
4
4
  def initialize(weekday:)
5
5
  @weekday = weekday
6
6
  end
@@ -9,10 +9,6 @@ module Repeatable
9
9
  date.wday == weekday
10
10
  end
11
11
 
12
- def to_h
13
- { weekday: { weekday: weekday } }
14
- end
15
-
16
12
  private
17
13
 
18
14
  attr_reader :weekday
@@ -1,6 +1,6 @@
1
1
  module Repeatable
2
2
  module Expression
3
- class WeekdayInMonth < Base
3
+ class WeekdayInMonth < Date
4
4
  def initialize(weekday:, count:)
5
5
  @weekday = weekday
6
6
  @count = count
@@ -10,10 +10,6 @@ module Repeatable
10
10
  day_matches?(date) && week_matches?(date)
11
11
  end
12
12
 
13
- def to_h
14
- { weekday_in_month: { weekday: weekday, count: count } }
15
- end
16
-
17
13
  private
18
14
 
19
15
  attr_reader :weekday, :count
@@ -25,7 +25,7 @@ module Repeatable
25
25
  end
26
26
 
27
27
  def expression_for(key, value)
28
- klass = "repeatable/expression/#{key}".classify.safe_constantize
28
+ klass = expression_klass(key.to_s)
29
29
  case klass
30
30
  when nil
31
31
  fail(ParseError, "Unknown mapping: Can't map key '#{key.inspect}' to an expression class")
@@ -40,5 +40,14 @@ module Repeatable
40
40
  def symbolize_keys(hash)
41
41
  hash.each_with_object({}) { |(k, v), a| a[k.to_sym] = v }
42
42
  end
43
+
44
+ def expression_klass(string)
45
+ camel_cased_string = string
46
+ .capitalize
47
+ .gsub(/(?:_)(?<word>[a-z\d]+)/i) { Regexp.last_match[:word].capitalize }
48
+ Repeatable::Expression.const_get(camel_cased_string)
49
+ rescue NameError => e
50
+ raise if e.name && e.name.to_s != camel_cased_string
51
+ end
43
52
  end
44
53
  end
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext/string/inflections'
2
-
3
1
  module Repeatable
4
2
  class Schedule
5
3
  def initialize(arg)
@@ -44,7 +42,11 @@ module Repeatable
44
42
  expression.to_h
45
43
  end
46
44
 
47
- private
45
+ def ==(other)
46
+ other.is_a?(self.class) && expression == other.expression
47
+ end
48
+
49
+ protected
48
50
 
49
51
  attr_reader :expression
50
52
  end
@@ -1,3 +1,3 @@
1
1
  module Repeatable
2
- VERSION = '0.3.0'
2
+ VERSION = '0.4.0'
3
3
  end
data/lib/repeatable.rb CHANGED
@@ -13,6 +13,7 @@ require 'repeatable/parse_error'
13
13
  require 'repeatable/expression'
14
14
  require 'repeatable/expression/base'
15
15
 
16
+ require 'repeatable/expression/date'
16
17
  require 'repeatable/expression/weekday'
17
18
  require 'repeatable/expression/weekday_in_month'
18
19
  require 'repeatable/expression/day_in_month'
data/repeatable.gemspec CHANGED
@@ -16,8 +16,6 @@ Gem::Specification.new do |spec|
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
17
  spec.require_paths = ['lib']
18
18
 
19
- spec.add_dependency 'activesupport', '>= 3.0'
20
-
21
19
  spec.add_development_dependency 'bundler', '~> 1.6'
22
20
  spec.add_development_dependency 'rake', '~> 10.0'
23
21
  spec.add_development_dependency 'rspec', '~> 3.0'
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: repeatable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mo Lawson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-11 00:00:00.000000000 Z
11
+ date: 2015-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: activesupport
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '3.0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '3.0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: bundler
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -77,6 +63,7 @@ files:
77
63
  - ".gitignore"
78
64
  - ".rspec"
79
65
  - ".travis.yml"
66
+ - CHANGELOG.md
80
67
  - Gemfile
81
68
  - LICENSE.txt
82
69
  - README.md
@@ -87,6 +74,7 @@ files:
87
74
  - lib/repeatable/conversions.rb
88
75
  - lib/repeatable/expression.rb
89
76
  - lib/repeatable/expression/base.rb
77
+ - lib/repeatable/expression/date.rb
90
78
  - lib/repeatable/expression/day_in_month.rb
91
79
  - lib/repeatable/expression/intersection.rb
92
80
  - lib/repeatable/expression/range_in_year.rb
@@ -124,3 +112,4 @@ signing_key:
124
112
  specification_version: 4
125
113
  summary: Describe recurring event schedules and calculate their occurrences
126
114
  test_files: []
115
+ has_rdoc: