toolcase 0.1.0 → 0.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: be3b662dfb690e6efe28a29f6f71be36875a97b46db08b64dcd3e8567aa97191
4
- data.tar.gz: ff85f0cf1911494e70209b1f65a34dd20e4efbf0dd79293fe8a1a33fd266dc39
3
+ metadata.gz: 42ab4cde5229fee97fb5723d029c109caa0f20932fa4b9e6dbc17e7a1aec22ed
4
+ data.tar.gz: 5bb7a33c4b6c9ec54c5d456d705f78a4ec1b642bba831428daa78b32357733a5
5
5
  SHA512:
6
- metadata.gz: 8980d73de1ff37211cd66de46b8f3fc78f4edcad93cdae6bdbbb625b5452344c0c53990423abac7684608aadef6a18b8c664b6e1d79261d6b2b8ac9ad68dece0
7
- data.tar.gz: 5f9e7d32cf5dd1c35872dfbe7e10b59355bcb00e85097ed8ed44115ab5176dbcfd94662c783d97cdf19bef5f99f6d823d60f2ff8adf0e9e97e48ed59dfcdd6ff
6
+ metadata.gz: 229e6fc407eae590b1403245be100df24839c66614e3dfcbaccb9fc43365eb35286e0e494d7f453e25e5ffec0bc29146474caf01a1c60cd1c67a2956d513cb27
7
+ data.tar.gz: 4668874433002a46ed9b173b1d3e8735500d0c64513b8ed42d1c3a19147fc3b8fcdddeb3a62b9d00f296244d2cc81c513b366c6cc79680cac770d38a28a36655
data/.rubocop.yml CHANGED
@@ -1,16 +1,5 @@
1
- Style/StringLiterals:
2
- Enabled: true
3
- EnforcedStyle: double_quotes
4
-
5
- Style/StringLiteralsInInterpolation:
6
- Enabled: true
7
- EnforcedStyle: double_quotes
8
-
9
- Layout/LineLength:
10
- Max: 120
11
-
12
1
  AllCops:
13
- TargetRubyVersion: 2.3
2
+ TargetRubyVersion: 2.5
14
3
  NewCops: enable
15
4
 
16
5
  Style/StringLiterals:
@@ -29,3 +18,7 @@ Style/SingleLineMethods:
29
18
 
30
19
  Metrics/AbcSize:
31
20
  Max: 20
21
+
22
+ Metrics/MethodLength:
23
+ Exclude:
24
+ - 'test/registry_modifications_test.rb'
data/README.md CHANGED
@@ -19,7 +19,90 @@ And then execute:
19
19
 
20
20
  ## Usage
21
21
 
22
- TODO: Write usage instructions here
22
+ Extend a class to convert it into a strategy factory:
23
+
24
+ ```ruby
25
+ class Factory
26
+ extend Toolcase::Registry
27
+
28
+ register Linux
29
+ register Windows
30
+ register MacOS
31
+ register { |it| it.do_something }
32
+
33
+ default InvalidOS
34
+ end
35
+ ```
36
+
37
+ The `register` method adds an object to the registry. It can be a block or proc.
38
+
39
+ A default object can be assigned using the `default` method.
40
+ The default object, if present, will be returned by default in any search that no object is found.
41
+ This applies for the `find_by` and `[]` methods.
42
+
43
+ `register` methods has the following options:
44
+
45
+ ```ruby
46
+ class Factory
47
+ extend Toolcase::Registry
48
+
49
+ register Linux, tag: :OS # Registries can be classified with a tag.
50
+ register OtherStuff, id: :otherstuff # An item can have an identifier.
51
+ end
52
+ ```
53
+
54
+ An object can be located in different ways:
55
+
56
+ ```ruby
57
+ # By id.
58
+ Factory[:otherstuff]
59
+
60
+ # Using the find_by function, which will search through all registries.
61
+ Factory.find_by { |object| object.handle?(*args) }
62
+
63
+ # Search only through items with a specific tag.
64
+ Factory.find_by(:OS) { |object| object.handle?(*args) }
65
+
66
+ # Look up if an specific object belongs to the registry.
67
+ Factory.include?(object)
68
+
69
+ # Look up if an specific object is present in a specific tag.
70
+ Factory.include?(object, :OS)
71
+
72
+ # Get all registries.
73
+ Factory.registries
74
+
75
+ # Get all tagged registries.
76
+ Factory.registries(:OS)
77
+ ```
78
+
79
+ If another class inherits from the Factory, its registries are inherited too.
80
+ An useful use case is a validator registry, with common validators in base classes,
81
+ and specific validators in concrete classes.
82
+
83
+ ```ruby
84
+ class BaseRegistry
85
+ extend Toolcase::Registry
86
+
87
+ register BaseValidator
88
+ register NonEmpty
89
+ end
90
+
91
+ class SpecificRegistry < BaseRegistry
92
+ register SpecificValidator
93
+ end
94
+
95
+ SpecificRegistry.size # Returns 3.
96
+ ```
97
+
98
+ An item can be replaced or removed using the item id or the item directly.
99
+
100
+ ```ruby
101
+ Factory.replace(:linux, Ubuntu)
102
+ Factory.replace(Linux, Ubuntu)
103
+ Factory.remove(:windows)
104
+ Factory.remove(Windows)
105
+ ```
23
106
 
24
107
  ## Development
25
108
 
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Toolcase
4
+ # Registry mixin. Allows to convert a class into a registrable container.
5
+ # It can then be used to register strategies/handlers and use the class as an abstract factory.
6
+ module Registry
7
+ def register(object = nil, id: nil, tag: :nil, &block)
8
+ element = nil
9
+ element = object unless object.nil?
10
+ element = block if block_given?
11
+
12
+ return if element.nil? || include?(element)
13
+
14
+ elements << element
15
+ tagged_elements[tag] << element
16
+ identifiers[id] = element unless id.nil?
17
+
18
+ element
19
+ end
20
+
21
+ def default(object = nil)
22
+ @default = object unless object.nil?
23
+ defined?(@default) ? @default : nil
24
+ end
25
+
26
+ def [](id)
27
+ identifiers.fetch(id, default)
28
+ end
29
+
30
+ def find_by(tag = nil, &block)
31
+ container(tag).find(-> { default }, &block)
32
+ end
33
+
34
+ def include?(object, tag = nil)
35
+ container(tag).include?(object)
36
+ end
37
+
38
+ def size(tag = nil)
39
+ container(tag).size
40
+ end
41
+
42
+ def replace(old_object_or_id, new_object)
43
+ resolve_object_or_id(old_object_or_id) do |id, element|
44
+ identifiers[id] = new_object unless id.nil?
45
+ elements[elements.index(element)] = new_object
46
+
47
+ tagged_list = find_in_tagged(element)
48
+ tagged_list[tagged_list.index(element)] = new_object unless tagged_list.nil?
49
+ end
50
+ end
51
+
52
+ def remove(object_or_id)
53
+ resolve_object_or_id(object_or_id) do |id, element|
54
+ identifiers.delete(id)
55
+ elements.delete(element)
56
+ find_in_tagged(element)&.delete(element)
57
+ end
58
+ end
59
+
60
+ def inherited(child)
61
+ super
62
+ child.elements.concat(registries)
63
+ child.tagged_elements.merge!(tagged_elements)
64
+ child.identifiers.merge!(identifiers)
65
+ child.default(default)
66
+ end
67
+
68
+ def registries(tag = nil)
69
+ container(tag).clone.freeze
70
+ end
71
+
72
+ protected
73
+
74
+ EMPTY = [].freeze
75
+
76
+ def elements
77
+ @elements ||= []
78
+ end
79
+
80
+ def resolve_object_or_id(obj_or_id)
81
+ id = identifiers.key?(obj_or_id) ? obj_or_id : identifiers.find { |_, value| value == obj_or_id }&.first
82
+ element = id.nil? ? obj_or_id : identifiers[id]
83
+ return unless include?(element)
84
+
85
+ yield(id, element)
86
+ end
87
+
88
+ def tagged_elements
89
+ @tagged_elements ||= Hash.new { |hash, key| hash[key] = [] }
90
+ end
91
+
92
+ def find_in_tagged(element)
93
+ tagged_elements.find { |_, list| list.include?(element) }&.last
94
+ end
95
+
96
+ def identifiers
97
+ @identifiers ||= {}
98
+ end
99
+
100
+ def container(tag)
101
+ return elements if tag.nil?
102
+
103
+ tagged_elements.key?(tag) ? tagged_elements[tag] : EMPTY
104
+ end
105
+ end
106
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Toolcase
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/toolcase.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "toolcase/version"
4
+ require_relative "toolcase/registry"
4
5
 
6
+ # Main module
5
7
  module Toolcase
6
- class Error < StandardError; end
7
- # Your code goes here...
8
8
  end
data/toolcase.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.summary = "Registry for handlers as a Strategy pattern implementation"
11
11
  spec.homepage = "https://github.com/enchf/toolcase"
12
12
  spec.license = "MIT"
13
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
14
14
 
15
15
  spec.metadata["homepage_uri"] = spec.homepage
16
16
  spec.metadata["source_code_uri"] = spec.homepage
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toolcase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - enchf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-24 00:00:00.000000000 Z
11
+ date: 2021-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -110,6 +110,7 @@ files:
110
110
  - bin/console
111
111
  - bin/setup
112
112
  - lib/toolcase.rb
113
+ - lib/toolcase/registry.rb
113
114
  - lib/toolcase/version.rb
114
115
  - toolcase.gemspec
115
116
  homepage: https://github.com/enchf/toolcase
@@ -127,7 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
128
  requirements:
128
129
  - - ">="
129
130
  - !ruby/object:Gem::Version
130
- version: 2.3.0
131
+ version: 2.5.0
131
132
  required_rubygems_version: !ruby/object:Gem::Requirement
132
133
  requirements:
133
134
  - - ">="