recurify 0.0.2 → 0.0.3

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: f67467f617bc9f0301b2adea071f0399f6764157
4
- data.tar.gz: b1406f9990dc5ce45a8b176b623f7ade80d0c2de
3
+ metadata.gz: 4307b3688528bbcb1af64ae77bf4280a234add0e
4
+ data.tar.gz: e299a294802143fafa24566269bb99ff30e6cff7
5
5
  SHA512:
6
- metadata.gz: 2866e6d97a2077b9161075adb1212aa83c6524f06a241b3803dd069c4c9c8a8c2e1d897834ffa612482689c662db88518fbf201174e0733d484320ae87b661c2
7
- data.tar.gz: 41175f2ce891a1dbc2e3b522ebdba54f0d10cacfbbed277fd2454fe6ab4776cd2ccf36a6d9f49f0592c5322c12561b01791ce559a5170426187581aa2f18b107
6
+ metadata.gz: f5fc6cac84aab3d11c52258492b3fe5848cfa25be00157c6f9ecb8a46f2b66caf2a8df44e8f7c3c2784d48a0f54c266320dfcc43398b0d441d103004e981a6b7
7
+ data.tar.gz: 54ed94321f48ed1a6a6340b9f2851f2974d9633622e7be2a4d03a8f1adef3af57d2ccc32caee9b887f2e87e036166db44c99952e81152b6e831e3356a84fbb8e
data/README.md CHANGED
@@ -7,8 +7,9 @@
7
7
  **Recurify is very much "work in progress" and shoudn't be used yet.**
8
8
 
9
9
  Recurify is a simple, light-weight, evaluator for Recurrence Rules. It takes a
10
- Recurrence Rule as input and returns an [`Enumerable`][enumerable], containing
11
- all [`Date`][date] objects resulting from this Rule in chronlogical order.
10
+ `Rule` as input and returns an [`Enumerable`][enumerable], yielding all
11
+ occurrences (i.e. simple [`Date`][date] objects) resulting from the `Rule`'s
12
+ evaluation in chronlogical order.
12
13
 
13
14
  [enumerable]: http://ruby-doc.org/core-2.2.3/Enumerable.html
14
15
  [date]: http://ruby-doc.org/stdlib-2.2.3/libdoc/date/rdoc/Date.html
@@ -23,11 +24,11 @@ all [`Date`][date] objects resulting from this Rule in chronlogical order.
23
24
  * `F` - **F**eature commits with functional changes.
24
25
  Example commit message: `F implement Rule#normalize`.
25
26
  * `B` - **B**ugfix commits for fixing broken stuff.
26
- Example commit message: `B consider Rule#count in Rule#==`
27
+ Example commit message: `B consider Rule#count in Rule#==`.
27
28
  * `R` - **R**efactoring commits without functional changes.
28
29
  Example commit message: `R memoize Rule#normalize for performance`.
29
30
  * `C` - **C**hore commits are for everything else.
30
- Example commit message: `C upgrade to latest version of rubocop`.
31
+ Example commit message: `C bump version to 1.0.0`.
31
32
 
32
33
  Prefixed commit messages may seem a bit strange at first. The intention is
33
34
  simply to keep functional and non-functional changes clearly apart. Therefore,
@@ -73,7 +73,7 @@ module Recurify
73
73
  # @param other [Rule]
74
74
  # @return [Boolean]
75
75
  def ==(other)
76
- normalize.attributes == other.normalize.attributes
76
+ normalized_attributes == other.normalized_attributes
77
77
  end
78
78
 
79
79
  # Convert +self+ to a +Hash+, representing the same +Rule+. Note, that
@@ -7,7 +7,7 @@ module Recurify
7
7
  #
8
8
  # @return [Boolean]
9
9
  def normalized?
10
- Rule::BASE_FREQUENCIES.include?(frequency)
10
+ attributes == normalized_attributes
11
11
  end
12
12
 
13
13
  # Returns +true+ if +self+ is denormalized. By definition, a +Rule+ is
@@ -42,6 +42,13 @@ module Recurify
42
42
  !finite?
43
43
  end
44
44
 
45
+ # Returns +true+ if and only if +self+ evaluates to a single occurrence.
46
+ #
47
+ # @return [Boolean]
48
+ def one?
49
+ starts_on == normalized_ends_on
50
+ end
51
+
45
52
  # Returns +true+ if +self+ starts before or on +upper+. If +upper == nil+,
46
53
  # it is interpreted as "positive infinity". In that case, +#starts_before?+
47
54
  # always returns +true+, because all +Rule+ objects must have a finite
@@ -4,68 +4,78 @@ module Recurify
4
4
  module RuleTranslation # :nodoc:
5
5
  extend Forwardable
6
6
 
7
- NORMALIZATION_MATRIX = {
8
- # Normalization is a no-op for base-frequencies ...
7
+ # Applicable frequency minimizations grouped by +#frequency+ ...
8
+ FREQUENCY_MINIMIZATION_MATRIX = {
9
9
  'daily' => { target_frequency: 'daily', interval_multiplier: 1 },
10
10
  'monthly' => { target_frequency: 'monthly', interval_multiplier: 1 },
11
- # But, it is more interesting for sugar-frequencies ...
12
11
  'weekly' => { target_frequency: 'daily', interval_multiplier: 7 },
13
12
  'quarterly' => { target_frequency: 'monthly', interval_multiplier: 3 },
14
13
  'yearly' => { target_frequency: 'monthly', interval_multiplier: 12 }
15
14
  }.freeze
16
15
 
17
- DENORMALIZATION_MATRIX = {
16
+ # Applicable frequency maximizations grouped by +#frequency+ and ordered by
17
+ # decreasing preferability ...
18
+ FREQUENCY_MAXIMIZATION_MATRIX = {
18
19
  'daily' => [
19
- # Applicable denormalizitions ordered by decreasing preferability ...
20
20
  { target_frequency: 'weekly', interval_divisor: 7 },
21
21
  { target_frequency: 'daily', interval_divisor: 1 }
22
22
  ],
23
23
  'weekly' => [
24
- # Applicable denormalizitions ordered by decreasing preferability ...
25
24
  { target_frequency: 'weekly', interval_divisor: 1 }
26
25
  ],
27
26
  'monthly' => [
28
- # Applicable denormalizitions ordered by decreasing preferability ...
29
27
  { target_frequency: 'yearly', interval_divisor: 12 },
30
28
  { target_frequency: 'quarterly', interval_divisor: 3 },
31
29
  { target_frequency: 'monthly', interval_divisor: 1 }
32
30
  ],
33
31
  'quarterly' => [
34
- # Applicable denormalizitions ordered by decreasing preferability ...
35
32
  { target_frequency: 'yearly', interval_divisor: 4 },
36
33
  { target_frequency: 'quarterly', interval_divisor: 1 }
37
34
  ],
38
35
  'yearly' => [
39
- # Applicable denormalizitions ordered by decreasing preferability ...
40
36
  { target_frequency: 'yearly', interval_divisor: 1 }
41
37
  ]
42
38
  }.freeze
43
39
 
44
- # Creates a new +Rule+, similar to +self+, but normalized. Note that
45
- # +#normalize+ is idempotent.
40
+ # Creates a new +Rule+, similar to +self+, but with minimized +#frequency+.
41
+ # Note that +#minimize_frequency+ is idempotent.
46
42
  #
47
- # Normalization means that +Rule+s with +#frequency+ ...
43
+ # Frequency minimization means that +Rule+s with +#frequency+ ...
48
44
  # * ... "weekly" are translated to +Rule+s with +#frequency+ "daily".
49
45
  # * ... "quarterly" are translated to +Rule+s with +#frequency+ "monthly".
50
46
  # * ... "yearly" are translated to +Rule+s with +#frequency+ "monthly".
51
47
  #
52
48
  # Additional translations may be added in the future.
53
49
  #
50
+ # @see FREQUENCY_MINIMIZATION_MATRIX
51
+ #
52
+ # @return [Rule]
53
+ def minimize_frequency
54
+ translate_with = FREQUENCY_MINIMIZATION_MATRIX[frequency]
55
+
56
+ substitute(
57
+ frequency: translate_with[:target_frequency],
58
+ interval: interval * translate_with[:interval_multiplier]
59
+ )
60
+ end
61
+
62
+ # Creates a new +Rule+, similar to +self+, but normalized. Note that
63
+ # +#normalize+ is idempotent.
64
+ #
54
65
  # @todo This method is not yet complete, because +#normalize+ should also
55
- # minify the +#ends_on+ and +#count+ attributes (if possible).
66
+ # minimize +#ends_on+ and +#count+ (if possible).
56
67
  #
57
68
  # @return [Rule]
58
69
  def normalize
59
- @_normalized_rule ||= begin
60
- translate_with = NORMALIZATION_MATRIX[frequency]
61
-
62
- substitute(
63
- frequency: translate_with[:target_frequency],
64
- interval: interval * translate_with[:interval_multiplier]
65
- )
66
- end
70
+ @_normalized_rule ||= minimize_frequency
67
71
  end
68
72
 
73
+ # @!method normalized_attributes
74
+ # @see Rule#attributes
75
+ # @see #normalize
76
+ # @return [Hash<Symbol,Object>]
77
+ def_delegator :normalize, :attributes, :normalized_attributes
78
+
69
79
  # @!method normalized_frequency
70
80
  # @see Rule#frequency
71
81
  # @see #normalize
@@ -90,32 +100,48 @@ module Recurify
90
100
  # @return [Date, nil]
91
101
  def_delegator :normalize, :ends_on, :normalized_ends_on
92
102
 
93
- # Creates a new +Rule+, similar to +self+, but denormalized. Note that
94
- # +#denormalized+ is idempotent.
103
+ # Creates a new +Rule+, similar to +self+, but with maximized +#frequency+.
104
+ # Note that +#maximize_frequency+ is idempotent.
95
105
  #
96
- # Denormalizion means that +Rule+s with +#frequency+ ...
106
+ # Frequency maximization means that +Rule+s with +#frequency+ ...
97
107
  # * ... "daily" are translated to +Rule+s with +#frequency+ "weekly".
98
108
  # * ... "monthly" are translated to +Rule+s with +#frequency+ "yearly".
99
109
  # * ... "monthly" are translated to +Rule+s with +#frequency+ "quarterly".
100
110
  #
101
111
  # Additional translations may be added in the future.
102
112
  #
103
- # Why +#denormalize+ at all? The idea is that denormalized +Rule+s are
104
- # easier to parse for humans. For instance, "every 7th week" is easier to
105
- # understand than "every 49th day".
113
+ # Why maximize the +#frequency+ at all? The idea is that frequency-maximized
114
+ # +Rule+s are easier to parse for humans. For instance, "every 7th week" is
115
+ # easier to understand than "every 49th day".
116
+ #
117
+ # @see FREQUENCY_MAXIMIZATION_MATRIX
106
118
  #
107
119
  # @return [Rule]
108
- def denormalize
109
- @_denormalized_rule ||= begin
110
- translate_with = find_best_denormalization
111
-
112
- substitute(
113
- frequency: translate_with[:target_frequency],
114
- interval: interval / translate_with[:interval_divisor]
115
- )
120
+ def maximize_frequency
121
+ translate_with = FREQUENCY_MAXIMIZATION_MATRIX[frequency].find do |c|
122
+ interval % c[:interval_divisor] == 0
116
123
  end
124
+
125
+ substitute(
126
+ frequency: translate_with[:target_frequency],
127
+ interval: interval / translate_with[:interval_divisor]
128
+ )
129
+ end
130
+
131
+ # Creates a new +Rule+, similar to +self+, but denormalized. Note that
132
+ # +#denormalized+ is idempotent.
133
+ #
134
+ # @return [Rule]
135
+ def denormalize
136
+ @_denormalized_rule ||= maximize_frequency
117
137
  end
118
138
 
139
+ # @!method denormalized_attributes
140
+ # @see Rule#attributes
141
+ # @see #denormalize
142
+ # @return [Hash<Symbol,Object>]
143
+ def_delegator :denormalize, :attributes, :denormalized_attributes
144
+
119
145
  # @!method denormalized_frequency
120
146
  # @see Rule#frequency
121
147
  # @see #denormalize
@@ -139,15 +165,5 @@ module Recurify
139
165
  # @see #denormalize
140
166
  # @return [Date, nil]
141
167
  def_delegator :denormalize, :ends_on, :denormalized_ends_on
142
-
143
- private
144
-
145
- # @see DENORMALIZATION_MATRIX
146
- # @return [Hash<Symbol, Object>]
147
- def find_best_denormalization
148
- DENORMALIZATION_MATRIX[frequency].find do |contender|
149
- normalize.interval % contender[:interval_divisor] == 0
150
- end
151
- end
152
168
  end
153
169
  end
@@ -1,3 +1,3 @@
1
1
  module Recurify # :nodoc:
2
- VERSION = '0.0.2'.freeze
2
+ VERSION = '0.0.3'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recurify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christoph Schiessl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-02 00:00:00.000000000 Z
11
+ date: 2015-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec