sideroo 1.1.0 → 1.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 03a7b294f185dedea2a5a2b24280df69d4102e54bdaf729819b4823205e7057c
4
- data.tar.gz: 654bca601be4cc8481d5be43410b96f3bf7029b3212828d89d183b593d9acd7d
3
+ metadata.gz: c03495a873770c5d552eb9c0ef4101f747f6e1783372eb9bd66c16c5bb407402
4
+ data.tar.gz: d75ddcb78b2604d202227557dc67fdbe32f5002da340e6c2dbfce31bf19adf12
5
5
  SHA512:
6
- metadata.gz: 19dafd77261755bfc811c4520f299b5b895ac4daaf2c4016e5d0172f794369c9a5574b397aa294dcf8420bea03fed7e6ee9f0b797a40828accb896fb52a6566c
7
- data.tar.gz: 592e26ba47f3e4547b7e57a4353c4d13b44158d1904fe09635d178b94f7ea41c200747e5d42faa1a3ea8dc0a95b2b92bd2a1adb4d2418d8355188b118a59afe1
6
+ metadata.gz: a2e61addab0caf170ee6f1ab5e064499565995c855777d1dcf2fe75ea11e40b925bd2ef978aeb2aaa1d7c31ffa9ee3236ac7f881d6cd6200e6655c880230d41a
7
+ data.tar.gz: 58441f5659b2bf72dca1289f538966a933793f7d9b2da0c4f2509a2d06d51324bfcf3a46c06df38d49cd33d46c39b4e36b3abddb25f78d36f476330755078601
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sideroo (1.1.0)
4
+ sideroo (1.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -15,11 +15,16 @@ This gem is aimed to provide
15
15
  example 'top_stories:us:romance'
16
16
  key_regex /^top_stories\:(\w{2})\:([^\:]+)$/ # OPTIONAL - read docs below
17
17
  end
18
+
19
+ TopStoriesCache.dimensions # ['country', 'category']
18
20
  ```
19
- - an **intuitive** Redis key initialization
21
+ - an **intuitive** Redis key initialization & `attr_accessor`
20
22
  ```rb
21
23
  cache = TopStoriesCache.new(country: 'us', category: 'romance')
22
24
  # instead of repeating key = "top_stories:#{country}:#{category}"
25
+
26
+ cache.country # us
27
+ cache.genre # romance
23
28
  ```
24
29
  - **object-oriented** methods for each Redis data type
25
30
  ```rb
@@ -566,22 +571,42 @@ cache = UserStoriesCache.new(...)
566
571
  cache.use_client(instance_redis_client)
567
572
  ```
568
573
 
574
+ ## 7. Advanced usages
575
+
576
+ ### 7.1. Dimension validations
577
+
578
+ To keep this gem thin, we have decided not to add explicit support for dimension validation.
579
+
580
+ However, `Sideroo` collaborates perfectly with `ActiveModel::Validations`. Please incorporate at your own needs.
581
+
582
+ ```rb
583
+ class TopStoriesCache < Sideroo::Set
584
+ include ActiveModel::Validations
585
+
586
+ key_pattern 'top_stories:{country}:{category}'
587
+ description 'Cache top stories by ID per country and category'
588
+ example 'top_stories:us:romance'
589
+
590
+ validates :country, length: 2
591
+ validates :category, regex: /^[^:]+$/
592
+ end
593
+ ```
569
594
 
570
- ## 7. Development
595
+ ## 8. Development
571
596
 
572
597
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
573
598
 
574
599
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
575
600
 
576
- ## 8. Contributing
601
+ ## 9. Contributing
577
602
 
578
603
  Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sideroo. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/sideroo/blob/master/CODE_OF_CONDUCT.md).
579
604
 
580
605
 
581
- ## 9. License
606
+ ## 10. License
582
607
 
583
608
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
584
609
 
585
- ## 10. Code of Conduct
610
+ ## 11. Code of Conduct
586
611
 
587
612
  Everyone interacting in the Sideroo project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/sideroo/blob/master/CODE_OF_CONDUCT.md).
@@ -1,6 +1,5 @@
1
1
  require "sideroo/version"
2
2
  require "sideroo/enumerator"
3
- require "sideroo/key_builder"
4
3
  require "sideroo/types/base"
5
4
  require "sideroo/types/bitmap"
6
5
  require "sideroo/types/hash"
@@ -14,6 +13,10 @@ module Sideroo
14
13
  class Error < StandardError; end
15
14
  class MissingKeys < ArgumentError; end
16
15
  class UnexpectedKeys < ArgumentError; end
16
+ class InvalidExample < StandardError; end
17
+ class InvalidKeyRegex < StandardError; end
18
+ class OutOfOrderConfig < StandardError; end
19
+ class PatternAlreadyDeclared < StandardError; end
17
20
 
18
21
  class Configuration
19
22
  attr_accessor :redis_client
@@ -15,19 +15,29 @@ module Sideroo
15
15
  end
16
16
 
17
17
  def key_pattern(*args)
18
- @key_pattern = args.first if args.count > 0
18
+ if args.count > 0
19
+ declare_key_pattern(args.first)
20
+ end
21
+
19
22
  @key_pattern
20
23
  end
21
24
 
22
25
  def key_regex(*args)
23
- @key_regex = args.first if args.count > 0
26
+ if args.count > 0
27
+ custom_key_regex_should_be_defined_before_example!
28
+ @key_regex = args.first
29
+ end
24
30
  @key_regex || default_key_regex
25
31
  end
26
32
 
27
- ## METADATA
33
+ # Provide example to test against key_pattern and key_regex.
34
+ # Strongly recommended. Please watch out for edge cases.
28
35
  #
29
36
  def example(*args)
30
- @example = args.first if args.count > 0
37
+ if args.count > 0
38
+ @example = args.first
39
+ validate_example_and_regex!
40
+ end
31
41
  @example
32
42
  end
33
43
 
@@ -37,9 +47,12 @@ module Sideroo
37
47
  end
38
48
 
39
49
  def key_attributes
40
- KeyBuilder.key_attributes(key_pattern)
50
+ regex = /\{([^\{\}]+)\}/
51
+ key_pattern.scan(regex).map(&:first)
41
52
  end
42
53
 
54
+ alias_method :dimensions, :key_attributes
55
+
43
56
  def redis_client(*args)
44
57
  @redis_client = args.first if args.count > 0
45
58
  @redis_client || Sideroo.redis_client
@@ -66,11 +79,19 @@ module Sideroo
66
79
  all.each(&:del)
67
80
  end
68
81
 
69
- def example_valid?
70
- example.nil? || example =~ key_regex
82
+ private
83
+
84
+ def declare_key_pattern(pattern)
85
+ raise Sideroo::PatternAlreadyDeclared unless key_pattern.nil?
86
+ @key_pattern = pattern
87
+ define_dimensions_as_attr_accessors
71
88
  end
72
89
 
73
- private
90
+ def define_dimensions_as_attr_accessors
91
+ dimensions.each do |dimension|
92
+ attr_accessor dimension
93
+ end
94
+ end
74
95
 
75
96
  def define_redis_method(method_name)
76
97
  define_method method_name do |*args|
@@ -91,6 +112,31 @@ module Sideroo
91
112
 
92
113
  Regexp.new("^#{regex_str}$")
93
114
  end
115
+
116
+ def custom_key_regex_should_be_defined_before_example!
117
+ return if example.nil?
118
+ message = 'Custom key regex should be defined before example'
119
+ raise Sideroo::OutOfOrderConfig, message
120
+ end
121
+
122
+ # Validate if the provided example matches key regex
123
+ #
124
+ def validate_example_and_regex!
125
+ return if example.nil?
126
+ example_valid = example =~ key_regex
127
+
128
+ unless example_valid
129
+ message = "Example does not match key regex: #{key_regex}"
130
+ raise Sideroo::InvalidExample, message
131
+ end
132
+
133
+ values = example.scan(key_regex).first
134
+
135
+ if values.count != dimensions.count
136
+ message = "Expected #{dimensions.count} dimensions, got #{values.count}"
137
+ raise Sideroo::InvalidKeyRegex, message
138
+ end
139
+ end
94
140
  end
95
141
 
96
142
  # Methods applied to all types
@@ -113,25 +159,40 @@ module Sideroo
113
159
  unlink
114
160
  ]
115
161
 
116
- attr_reader :key
117
-
118
162
  def initialize(arg = {})
119
- @key =
120
- case arg
121
- when ::String
122
- message = "Expected pattern #{self.class.key_pattern}, got #{arg}"
123
- raise(ArgumentError, message) if arg !~ self.class.key_regex
124
- arg
125
- when ::Hash
126
- attr_map = arg
127
- KeyBuilder.new(
128
- attr_map: attr_map,
129
- key_pattern: self.class.key_pattern,
130
- ).build
131
- else
132
- message = "Hash or String expected. #{arg.class} given."
133
- raise ArgumentError, message
163
+ case arg
164
+ when ::String
165
+ raw_key = arg
166
+ key_regex = self.class.key_regex
167
+
168
+ message = "Expected pattern #{key_pattern}, got #{arg}"
169
+ raise(ArgumentError, message) if raw_key !~ key_regex
170
+
171
+ values = raw_key.scan(key_regex).first
172
+ self.class.dimensions.zip(values).each do |dimension, value|
173
+ send("#{dimension}=", value)
134
174
  end
175
+ when ::Hash
176
+ attr_map = arg
177
+ attr_map.each do |dimension, value|
178
+ send("#{dimension}=", value)
179
+ end
180
+ else
181
+ message = "Hash or String expected. #{arg.class} given."
182
+ raise ArgumentError, message
183
+ end
184
+ end
185
+
186
+ def key
187
+ k = key_pattern
188
+
189
+ self.class.dimensions.each do |dimension|
190
+ term = "{#{dimension}}"
191
+ value = send(dimension)
192
+ k = k.gsub(term, value.to_s)
193
+ end
194
+
195
+ k
135
196
  end
136
197
 
137
198
  def redis_client=(client)
@@ -141,5 +202,29 @@ module Sideroo
141
202
  def redis_client
142
203
  @redis_client || self.class.redis_client
143
204
  end
205
+
206
+ private
207
+
208
+ def key_pattern
209
+ self.class.key_pattern
210
+ end
211
+
212
+ def validate_attrs!(attr_map)
213
+ provided_attrs = attr_map.keys.map(&:to_s)
214
+ key_attributes = self.class.key_attributes(key_pattern)
215
+
216
+ missing_attrs = key_attributes - provided_attrs
217
+ unexpected_attrs = provided_attrs - key_attributes
218
+
219
+ if missing_attrs.any?
220
+ msg = "Missing attributes: #{missing_attrs.join(', ')}"
221
+ raise MissingKeys, msg
222
+ end
223
+
224
+ if unexpected_attrs.any?
225
+ msg = "Unexpected attributes: #{unexpected_attrs.join(', ')}"
226
+ raise UnexpectedKeys, msg
227
+ end
228
+ end
144
229
  end
145
230
  end
@@ -1,3 +1,3 @@
1
1
  module Sideroo
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -18,7 +18,8 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.metadata["homepage_uri"] = spec.homepage
20
20
  spec.metadata["source_code_uri"] = "https://github.com/ntd251/sideroo"
21
- spec.metadata["changelog_uri"] = "https://github.com/ntd251/sideroo"
21
+ spec.metadata["changelog_uri"] = "https://github.com/ntd251/sideroo/releases"
22
+ spec.metadata["documentation_uri"] = "https://www.rubydoc.info/github/ntd251/sideroo"
22
23
 
23
24
  # Specify which files should be added to the gem when it is released.
24
25
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sideroo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Duong Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-07-19 00:00:00.000000000 Z
11
+ date: 2020-07-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: "\n Provide a declarative Redis key definition, intuitive key initialization,
14
14
  object-oriented methods for Redis data type, and auditable Redis key management.\n
@@ -32,7 +32,6 @@ files:
32
32
  - bin/setup
33
33
  - lib/sideroo.rb
34
34
  - lib/sideroo/enumerator.rb
35
- - lib/sideroo/key_builder.rb
36
35
  - lib/sideroo/types/base.rb
37
36
  - lib/sideroo/types/bitmap.rb
38
37
  - lib/sideroo/types/hash.rb
@@ -50,7 +49,8 @@ metadata:
50
49
  allowed_push_host: https://rubygems.org/
51
50
  homepage_uri: https://github.com/ntd251/sideroo
52
51
  source_code_uri: https://github.com/ntd251/sideroo
53
- changelog_uri: https://github.com/ntd251/sideroo
52
+ changelog_uri: https://github.com/ntd251/sideroo/releases
53
+ documentation_uri: https://www.rubydoc.info/github/ntd251/sideroo
54
54
  post_install_message:
55
55
  rdoc_options: []
56
56
  require_paths:
@@ -1,53 +0,0 @@
1
- module Sideroo
2
- class KeyBuilder
3
- attr_reader :attr_map
4
- attr_reader :key_pattern
5
-
6
- class << self
7
- def key_attributes(key_pattern)
8
- regex = /\{([^\{\}]+)\}/
9
- key_pattern.scan(regex).map(&:first)
10
- end
11
- end
12
-
13
- def initialize(attr_map:, key_pattern:)
14
- @attr_map = attr_map
15
- @key_pattern = key_pattern
16
- end
17
-
18
- def build
19
- validate_attrs!
20
- populate_key
21
- end
22
-
23
- private
24
-
25
- def validate_attrs!
26
- provided_attrs = attr_map.keys.map(&:to_s)
27
- key_attributes = self.class.key_attributes(key_pattern)
28
-
29
- missing_attrs = key_attributes - provided_attrs
30
- unexpected_attrs = provided_attrs - key_attributes
31
-
32
- if missing_attrs.any?
33
- msg = "Missing attributes: #{missing_attrs.join(', ')}"
34
- raise MissingKeys, msg
35
- end
36
-
37
- if unexpected_attrs.any?
38
- msg = "Unexpected attributes: #{unexpected_attrs.join(', ')}"
39
- raise UnexpectedKeys, msg
40
- end
41
- end
42
-
43
- def populate_key
44
- key = key_pattern
45
- attr_map.each do |attr, value|
46
- term = "{#{attr}}"
47
- key = key.gsub(term, value.to_s)
48
- end
49
-
50
- key
51
- end
52
- end
53
- end