register 0.5.3 → 0.5.4

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: e369eac31276624d538745280cb280fcbbe61b41
4
- data.tar.gz: f2927260fab0adef3486b976d0b8c25bb599abbe
3
+ metadata.gz: 9747f4557a3c6de92a37efff1e8a283a8715133a
4
+ data.tar.gz: 19eba97e52016589e2bc6ca9a7492f042d182940
5
5
  SHA512:
6
- metadata.gz: 37dd3f2dc9d2a523f7c8e153b8698268567d7bff81b1737e78caa06513e4e2ca81bb31343761130b906601077c10230066e118dc3d316b86f43b4c5037351712
7
- data.tar.gz: c78fb667da5066c918df19928326e03e2779fd7d36921aef1216ba77351e1dfce6ecf66c3da1b99bb22bc525228da89977966c4f588312414ff12fd4d8fdf6f4
6
+ metadata.gz: b47edbd458b251f7fa1532cfad381d9e8552ed01cf7709883a40003e9831c63e5f785a256bc2b0c9cfdaa3c79ddc790ffffae3f9f594ec2c8d026bc2c9546e5c
7
+ data.tar.gz: 0f7139bb74ba86e14e6d360c93c30f921b5b76a03dd326fa5246168a992aeeb5fe327f953b62cd57029bc57388f82af2f0b6ef07837e3ff732d1754a498752f4
@@ -0,0 +1 @@
1
+ --no-private --protected lib/**/*.rb - README.md LICENSE.txt
data/README.md CHANGED
@@ -12,9 +12,11 @@ A good example is a register of several connections to either *Redis* or *MemCac
12
12
 
13
13
  ## Usage
14
14
 
15
+ You need to create a module for each individual "store" — behind the scenes `Register` uses ruby `Hash`, but protects any write access to it using a local mutex to ensure thread-safety.
16
+
15
17
  ### Creating a Register
16
18
 
17
- To create a register module, just include `Register` in any ruby module:
19
+ To create a register module, just include `Register` in any of your custom ruby modules:
18
20
 
19
21
  ```ruby
20
22
  require 'register'
@@ -24,9 +26,13 @@ module Cache
24
26
  end
25
27
  ```
26
28
 
27
- ### Storing Items in the Register
29
+ ### Adding Items to the Register
30
+
31
+ To add items to the register, call the `#register` method on the module (or it's alias `.<<`, passing an array of identifiers first, followed by the actual item to store.
28
32
 
29
- To add items to the register, call the `<<` method, passing an array of identifiers, followed by the actual item to store. In other words, the last items of the argument array is the actual item stored against each of the identifiers passed before it.
33
+ In other words, the very last item of the argument array is the actual item stored against each of the keys passed in an array before it.
34
+
35
+ The `#register` method returns the item successfully stored, or raises one of several exceptions.
30
36
 
31
37
  ```ruby
32
38
 
@@ -34,66 +40,131 @@ To add items to the register, call the `<<` method, passing an array of identifi
34
40
  CacheStore = Struct.new(:name)
35
41
 
36
42
  # Register items associated with any one of the identifiers
37
- Cache.register :planetary, :cosmic, CacheStore.new(:saturn)
43
+ Cache.register :planetary,
44
+ :cosmic,
45
+ CacheStore.new(:saturn)
46
+ #=> #<struct CacheStore name=:saturn>
47
+
48
+ # Use the block syntax to define the value:
49
+ Cache.register(*%i[primary main rails deploy]) do
50
+ CacheStore.new(:primary)
51
+ end
52
+ #=> #<struct CacheStore name=:primary>
38
53
 
39
- # You can use << syntax which is an alias to #register, but
40
- # then use << to append the actual item
41
- Cache.<< %i[primary main rails deploy] << CacheStore.new(:primary)
54
+ # Use the << method alias instead (just ensure the proper
55
+ # grouping of the arguments)
56
+ Cache << %i[number].push(Math::PI)
57
+ #=> 3.141592653589793
42
58
 
43
- Cache.<< %i[durable secondary] << CacheStore.new(:secondary)
59
+ # Using double << with ()
60
+ Cache << (%i[durable secondary] << CacheStore.new(:secondary))
61
+ #=> #<struct CacheStore name=:secondary>
44
62
  ```
45
63
 
46
- ### Looking up (Fetching) Items from the Register
64
+ #### Exceptions while Adding Items
65
+
66
+ * `AlreadyRegisteredError` is thrown when the key is already in the store, and the option `:ignore_if_exists` is not passed to the `register()` method;
67
+
68
+ * `ReservedIdentifierError` is thrown upon an attempt to register a keyword that is reserved (i.e. clashes with one of the methods on the blank `Module`).
69
+
70
+
71
+ ### Fetching an Item from the Register
47
72
 
48
73
  There are two ways to fetch the previously-stored item:
49
74
 
50
75
  1. Using the `#for(:name)` method
76
+
51
77
  2. Using the auto-generated module-level accessor
52
78
 
53
79
  In the first example, we would call `Cache.for(:planetary)` to fetch the cache store, while in the second case we would call `Cache.planetary` method, which provides additional guarantees: if the method is not there, something is definitely wrong.
54
80
 
55
81
  ```ruby
56
- Cache.planetary.name should eq(:saturn)
57
- Cache.primary === Cache.main === Cache.rails === Cache.deploy
82
+ Cache.cosmic
83
+ # => #<struct CacheStore name=:saturn>
84
+ Cache.planetary.name
85
+ # => :saturn
86
+ Cache.primary == Cache.main == Cache.rails == Cache.deploy
87
+ # => true
58
88
  Cache.durable.name = 'DURABLE'
59
- Cache.secondary.name # => 'DURABLE'
89
+ # => 'DURABLE'
90
+ Cache.secondary.name
91
+ # => 'DURABLE'
60
92
  ```
61
93
 
62
- Here is a more complete RSPec example:
94
+ #### Exceptions while Fetching Items
95
+
96
+ * `NoSuchIdentifierError` is thrown upon lookup with method `#for` when no requested key was found in the store;
97
+
98
+ ## Contributing
99
+
100
+ * Fork the project.
101
+ * Make your feature addition or bug fix.
102
+ * Add specs for it, as without tests the PR will be rejected.
103
+ * Do not change the version.
104
+ * Send a pull request, with a well worded description.
105
+
106
+
107
+ There are some additional methods that will help you debug should things go weird:
108
+
109
+ ### Additional Methods: `#keys` and `#values`
110
+
111
+ These two methods proxy into the underlying `Hash`. The `#values` method returns the uniq'd array of the values.
63
112
 
64
113
  ```ruby
65
- require 'rspec'
66
- require 'rspec/its'
67
- RSpec.describe Cache do
68
- subject(:cache) { Cache }
69
- its(:planetary) { should eq CachStore.new(:saturn) }
70
- its(:deploy) { should eq CachStore.new(:primary) }
71
- its(:durable) { should eq CachStore.new(:secondary) }
72
- it 'should also respond to #for' do
73
- expect(cache.for(:secondary)).to eq(CacheStore(:secondary))
74
- end
75
- end
114
+ # ap Cache.keys
115
+ [
116
+ [0] :planetary,
117
+ [1] :cosmic,
118
+ [2] :primary,
119
+ [3] :main,
120
+ [4] :rails,
121
+ [5] :deploy,
122
+ [6] :durable,
123
+ [7] :secondary,
124
+ [8] :number
125
+ ]
126
+ # ap Cache.store.values.uniq
127
+ [
128
+ [0] #<Struct:CacheStore:0x7facd107c800
129
+ name = :saturn
130
+ >,
131
+ [1] #<Struct:CacheStore:0x7facd2836c98
132
+ name = :primary
133
+ >,
134
+ [2] #<Struct:CacheStore:0x7facd281fa98
135
+ name = :secondary
136
+ >,
137
+ [3] 3.141592653589793
138
+ ]
76
139
  ```
77
-
140
+
141
+ ### Internal Storage
142
+
143
+ This gem uses a plain ruby `Hash` to store the values, but protects write access with a `Mutex`.
144
+
145
+ While it is not advisable to manipulate the underlying storage, you can access it via `Cache.send(:store)`, i.e:
146
+
147
+ ```ruby
148
+ Cache.send(:store).class
149
+ # => Hash
150
+ ```
151
+
78
152
  ## Installation
79
153
 
80
154
  gem install register
155
+
156
+ Or if you are using Bundler, add the following to your `Gemfile`:
81
157
 
82
- ## Note on Patches and Pull Requests
83
-
84
- * Fork the project.
85
- * Make your feature addition or bug fix.
86
- * Add tests for it. This is important so I don't break it in a future version unintentionally.
87
- * Commit, do not mess with rakefile, version, or history. If you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull.
88
- * Send a pull request. Bonus points for topic branches.
158
+ gem 'register'
89
159
 
90
160
  ## Copyright
91
161
 
92
- Copyright &copy; 2017 Konstantin Gredeskoul. See LICENSE for details.
162
+ Copyright &copy; 2017 Konstantin Gredeskoul. See [LICENSE](LICENSE.txt) for details.
93
163
 
94
164
  ## Contributors
95
165
 
96
166
  * [Konstantin Gredeskoul](https://github.com/kigster)
167
+ * You?
97
168
 
98
169
 
99
170
 
data/Rakefile CHANGED
@@ -1,23 +1,35 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
3
  require 'yard'
4
+ require 'colored2'
4
5
 
5
6
  def shell(*args)
6
- puts "running: #{args.join(' ')}"
7
+ puts "running: #{args.join(' ').blue.bold}".yellow
7
8
  system(args.join(' '))
8
9
  end
9
10
 
11
+ module Register
12
+ DIST_DIRS=%w(lib)
13
+ BIN_DIRS=%w()
14
+ end
15
+
10
16
  task :permissions do
11
17
  shell('rm -rf pkg/')
12
- shell('chmod -v o+r,g+r * */* */*/* */*/*/* */*/*/*/* */*/*/*/*/*')
13
- shell('chmod -v o+x,g+x exe/* bin/*')
14
- shell("find . -type d -exec chmod o+x,g+x {} \\;")
18
+ Register::BIN_DIRS.each do |dir|
19
+ shell("chmod -v o+rx,g+rx #{dir}/*")
20
+ end
21
+
22
+ Register::DIST_DIRS.each do |dir|
23
+ shell("chmod -v o+rx,g+rx #{dir}")
24
+ shell("find #{dir} -name '[a-z]*' -type d -exec chmod o+rx,g+rx {} \\; -print")
25
+ shell("find #{dir} -type f -exec chmod o+r,g+r {} \\; -print")
26
+ end
15
27
  end
16
28
 
17
29
  task :build => :permissions
18
30
 
19
31
  YARD::Rake::YardocTask.new(:doc) do |t|
20
- t.files = %w(lib/**/*.rb exe/*.rb - README.md LICENSE)
32
+ t.files = %w(lib/**/*.rb exe/*.rb - README.md LICENSE.txt )
21
33
  t.options.unshift('--title','Register - An easy way to create Mudule-level accessors to global resources')
22
34
  t.after = ->() { exec('open doc/index.html') }
23
35
  end
@@ -1,31 +1,73 @@
1
1
  require 'register/version'
2
2
  require 'colored2'
3
+ require 'forwardable'
4
+
5
+ # **Register** is a tiny library that can be included in a module
6
+ # that is to become a Façade to several application globals via
7
+ # auto-generated module-level methods.
8
+ #
9
+ # A good example is a register of several connections to either
10
+ # *Redis* or *MemCached*, for example you might have a short-term
11
+ # memcached connection with a short default expiration TTL, and a
12
+ # longer-living one that requires sweeping to clean. You could
13
+ # use `Register` to wrap access to these singletons in
14
+ # `MyModule.cache_type` accessors.
15
+ #
16
+ # Usage
17
+ # =====
18
+ #
19
+ # To create a register module, just include `Register` in any
20
+ # of your custom ruby modules:
21
+ #
22
+ # require 'register'
23
+ #
24
+ # module Cache
25
+ # include Register
26
+ # end
27
+ #
28
+ # Cache.register :rails, Rails.cache
29
+ # Cache.register :durable, ActiveSupport::Cache::DalliStore.new(
30
+ # ENV['MEMCACHED_HOSTS'] ? ENV['MEMCACHED_HOSTS'].split(',') : %w[localhost:11211],
31
+ # namespace: 'v1',
32
+ # socket_timeout: 0.2,
33
+ # expires_in: 0, # never expire
34
+ # keepalive: true,
35
+ # compress: true,
36
+ # failover: true
37
+ # )
38
+ #
39
+ # Cache.rails # => Rails.cache
40
+ # Cache.durable # => DalliStore, etc.
41
+ #
3
42
  module Register
4
43
  class RegisterError < StandardError; end
5
44
  class AlreadyRegisteredError < RegisterError; end
6
45
  class NoSuchIdentifierError < RegisterError; end
7
46
  class ReservedIdentifierError < RegisterError; end
8
47
 
9
- module DummyModule
10
- end
11
-
12
- RESERVED = (DummyModule.methods << %i[for register << add_method]).flatten!.freeze
48
+ RESERVED = (Register.methods + %i[for register keys values << add_method]).flatten.uniq.freeze
13
49
 
14
50
  def self.included(klass)
15
51
  klass.instance_eval do
16
52
  @store = Hash.new
17
53
  @mutex = Mutex.new
18
54
  class << self
19
- attr_accessor :store, :mutex
20
- def <<(*names, &block)
55
+ extend Forwardable
56
+ def_delegators :@store, :keys
57
+ attr_accessor :mutex
58
+
59
+ def << *names, **opts, &block
21
60
  names.flatten!
22
61
  item = block ? yield(self) : names.pop
23
- validate_existing_keys!(names)
24
62
  validate_reserved_keys!(names)
25
- names.each do |n|
26
- store[n] = item
27
- add_method(n)
63
+ @mutex.synchronize do
64
+ validate_existing_keys!(names, opts)
65
+ names.each do |n|
66
+ store[n] = item
67
+ add_method(n)
68
+ end
28
69
  end
70
+ item
29
71
  end
30
72
 
31
73
  alias register <<
@@ -38,19 +80,25 @@ module Register
38
80
  store[id]
39
81
  end
40
82
 
83
+ def values
84
+ store.values.uniq
85
+ end
86
+
41
87
  private
42
88
 
89
+ def store
90
+ @store
91
+ end
92
+
43
93
  def add_method(id)
44
94
  return unless id.is_a?(Symbol)
45
- @mutex.synchronize do
46
- unless self.respond_to?(id)
47
- line_no = __LINE__
48
- method_defs = %Q!
95
+ unless self.respond_to?(id)
96
+ line_no = __LINE__
97
+ method_defs = %Q!
49
98
  def self.#{id}
50
99
  store[:#{id}]
51
100
  end\n!
52
- module_eval method_defs, __FILE__, line_no
53
- end
101
+ module_eval method_defs, __FILE__, line_no
54
102
  end
55
103
  end
56
104
 
@@ -61,14 +109,12 @@ module Register
61
109
  end
62
110
  end
63
111
 
64
- def validate_existing_keys!(names)
112
+ def validate_existing_keys!(names, opts = {})
65
113
  already = names.select { |n| store.key?(n) }
66
- unless already.empty?
114
+ if !already.empty? && opts[:ignore_if_exists].nil?
67
115
  raise AlreadyRegisteredError, "The following keys are already in the registry: #{already}"
68
116
  end
69
117
  end
70
-
71
-
72
118
  end
73
119
  end
74
120
  end
@@ -1,3 +1,3 @@
1
1
  module Register
2
- VERSION = '0.5.3'.freeze
2
+ VERSION = '0.5.4'.freeze
3
3
  end
@@ -21,7 +21,9 @@ Gem::Specification.new do |spec|
21
21
  spec.add_development_dependency 'simplecov'
22
22
  spec.add_development_dependency 'codeclimate-test-reporter'
23
23
  spec.add_development_dependency 'colored2'
24
+ spec.add_development_dependency 'irbtools'
24
25
  spec.add_development_dependency 'yard'
26
+ spec.add_development_dependency 'yard-rspec'
25
27
  spec.add_development_dependency 'awesome_print'
26
28
  spec.add_development_dependency 'bundler', '~> 1.15'
27
29
  spec.add_development_dependency 'rake', '~> 10.0'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: register
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: irbtools
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: yard
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,20 @@ dependencies:
66
80
  - - ">="
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: awesome_print
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -152,6 +180,7 @@ files:
152
180
  - ".rspec"
153
181
  - ".rubocop.yml"
154
182
  - ".travis.yml"
183
+ - ".yardopts"
155
184
  - Gemfile
156
185
  - LICENSE.txt
157
186
  - README.md