zyra 0.0.2 → 1.0.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: 5cb11a8449da1cdc0b87c0600b96c3b7e9c76b024b95bc4a722b764570296f50
4
- data.tar.gz: 5848a55463e899d78ff4c28dd6ae81993916cd449b3dfd35692bb47f46777452
3
+ metadata.gz: 7c8f905bbdb0fec56487d7be0a0999983394975cfe3878397ffa7b12f8b43229
4
+ data.tar.gz: ef03ada86291579a39b0f1dbb9b4bd6dc868090752240522eb22a5c89d6ad559
5
5
  SHA512:
6
- metadata.gz: 5b13ca88db8dfa338c68f4af3177d39202d2274a88ec0738a7146b59619e6ccb3369277280e0954fe68150e43ed3f8aac1566d95802c79a552b74db340235f96
7
- data.tar.gz: ff5cfc24cbc93e90107ec311b1c6baf25c9fc81d9e8aba0bb89ba1f2d876cf93198f6769a5fcf21d3db5db670e4ad399a1762081a41cf21cdd848d46bbf0dc8f
6
+ metadata.gz: 6132bf64c4fb482e408c24d6e84964bc7862ed31890ee3257608476ee659e63252db0f01602da4afe367ce7a8f6661c65d7099634a9982aa97b20c6d10817d29
7
+ data.tar.gz: 8b79a9c2f74a31b83e50e98571920f6b3d2e8ac441c58a64e88dd9224a2b5bfe7a5bd043bc5b131c63d2857d6840ff1b9e8f0f1fa1e1009bc213a7fcc808d29b
data/.rubocop.yml CHANGED
@@ -20,6 +20,7 @@ RSpec/AlignLeftLetBrace:
20
20
  RSpec/DescribedClass:
21
21
  Exclude:
22
22
  - 'spec/integration/yard/**/*_spec.rb'
23
+ - 'spec/integration/readme/**/*_spec.rb'
23
24
 
24
25
  RSpec/ExampleLength:
25
26
  Exclude:
data/README.md CHANGED
@@ -9,9 +9,15 @@ Zyra
9
9
 
10
10
  ![zyra](https://raw.githubusercontent.com/darthjee/zyra/master/zyra.jpg)
11
11
 
12
+ Zyra is intented to easy the seeding stage of projects by ensuring an
13
+ entity exists without having to reinsert it every time in the database
14
+
15
+ The process is done by registering a model class, then performing
16
+ a creation in case of missing the entry
17
+
12
18
  Yard Documentation
13
19
  -------------------
14
- [https://www.rubydoc.info/gems/zyra/0.0.2](https://www.rubydoc.info/gems/zyra/0.0.2)
20
+ [https://www.rubydoc.info/gems/zyra/1.0.0](https://www.rubydoc.info/gems/zyra/1.0.0)
15
21
 
16
22
  Installation
17
23
  ---------------
@@ -31,3 +37,63 @@ Installation
31
37
  ```bash
32
38
  bundle install zyra
33
39
  ```
40
+
41
+ Usage
42
+ -----
43
+
44
+ The usage is done by registering a model, adding hooks
45
+ and calling `find_or_create` and passing a block to be executed
46
+ after
47
+
48
+ ```ruby
49
+ Zyra
50
+ .register(User, find_by: :email)
51
+ .on(:build) do |user|
52
+ user.reference = SecureRandom.hex(16)
53
+ end
54
+
55
+ attributes = {
56
+ email: 'usr@srv.com',
57
+ name: 'Some User',
58
+ password: 'pass'
59
+ }
60
+
61
+ user = Zyra.find_or_create(:user, attributes) do |usr|
62
+ usr.update(attributes)
63
+ end
64
+
65
+ # returns an instance of User that is persisted in the database
66
+ # user.email is the key as 'usr@srv.com'
67
+ # user.name will always be updated to 'Some User'
68
+ # user.password will always be updated to 'pass'
69
+ # user.reference will be generated in the first time, and never again regenerated
70
+ ```
71
+
72
+ ## Hooks
73
+
74
+ hooks can be registered when registering a model or after to be executed in 4
75
+ points, `found`, `build`, `create` and `return`
76
+
77
+ ```ruby
78
+ Zyra
79
+ .register(User, find_by: :email)
80
+ .on(:build) do |user|
81
+ user.posts.build(name: 'first', content: 'some content')
82
+ end
83
+
84
+ Zyra.on(:user, :return) do |user|
85
+ user.update(reference: SecureRandom.hex(16))
86
+ end
87
+
88
+ attributes = {
89
+ email: 'usr@srv.com',
90
+ name: 'Some User',
91
+ password: 'pass'
92
+ }
93
+
94
+ user = Zyra.find_or_create(:user, attributes).reload
95
+
96
+ # Returns a User with email 'usr@srv.com'
97
+ # Creates a post for the user, only in the first time
98
+ # Regenerates the reference every time the code is ran
99
+ ```
data/config/yardstick.yml CHANGED
@@ -1,4 +1,4 @@
1
- threshold: 96
1
+ threshold: 100
2
2
  require_exact_threshold: false
3
3
  rules:
4
4
  ApiTag::Presence:
@@ -15,25 +15,17 @@ rules:
15
15
  exclude: []
16
16
  ExampleTag:
17
17
  enabled: true
18
- exclude:
19
- - Zyra.register
20
- - Zyra.after
21
- - Zyra.build
22
- - Zyra.create
23
- - Zyra::Builder#after
24
- - Zyra::Builder#build
25
- - Zyra::Builder#create
26
- - Zyra::Registry#register
18
+ excludei: []
27
19
  ReturnTag:
28
20
  enabled: true
29
- exclude:
30
- - Zyra.after
31
- - Zyra.build
32
- - Zyra.create
21
+ exclude: []
33
22
  Summary::Presence:
34
23
  enabled: true
35
24
  exclude:
36
- - Zyra::Builder#initialize
25
+ - Zyra::Finder#initialize
26
+ - Zyra::Creator#initialize
27
+ - Zyra::FinderCreator#initialize
28
+ - Zyra::Registry#initialize
37
29
  Summary::Length:
38
30
  enabled: true
39
31
  exclude: []
@@ -5,15 +5,16 @@ module Zyra
5
5
  # @author Darthjee
6
6
  #
7
7
  # Class responsible for building a model
8
- class Builder
8
+ class Creator
9
9
  # @param model_class [Class] Model class to be initialized
10
10
  # into a model
11
- def initialize(model_class)
11
+ # @param event_registry [Jace::Registry] event registry to handle events
12
+ def initialize(model_class, event_registry:)
12
13
  @model_class = model_class
14
+ @event_registry = event_registry
13
15
  end
14
16
 
15
- # @api public
16
- # Builds an instance of the registered model class
17
+ # Creates an instance of the registered model class
17
18
  #
18
19
  # @param attributes [Hash] attributes to be set in the model
19
20
  # @param block [Proc] block to be ran after where more attributes
@@ -22,22 +23,6 @@ module Zyra
22
23
  # @yield [Object] Instance of the model class
23
24
  #
24
25
  # @return [Object] an instance of model class
25
- def build(**attributes, &block)
26
- block ||= proc {}
27
-
28
- model_class.new(attributes).tap(&block).tap do |model|
29
- event_registry.trigger(:build, model)
30
- end
31
- end
32
-
33
- # @api public
34
- # Creates an instance of the registered model class
35
- #
36
- # This behaves like {#build}, but persists the entry
37
- #
38
- # @param (see #build)
39
- # @yield (see #build)
40
- # @return (see #build)
41
26
  def create(**attributes, &block)
42
27
  model = build(**attributes, &block)
43
28
 
@@ -46,44 +31,30 @@ module Zyra
46
31
  end
47
32
  end
48
33
 
49
- # @api public
50
- # Register a handler on a certain event
51
- #
52
- # Possible events are +build+, +create+
53
- #
54
- # @param event [Symbol,String] event to be watched.
55
- # @param block [Proc] block to be executed when the event is called
56
- #
57
- # @yield [Object] the model built
58
- #
59
- # @return [Builder] the builder itself
60
- def after(event, &block)
61
- tap { event_registry.register(event, &block) }
62
- end
34
+ protected
63
35
 
64
- # Checks if another builder is equal to the current builder
65
- #
66
- # This is used mostly for rspec expectations
67
- #
68
- # @param other [Object] other object to be compared
36
+ # @private
37
+ # Builds an instance of the registered model class
69
38
  #
70
- # @return [TrueClass,FalseClass]
71
- def ==(other)
72
- return unless other.class == self.class
39
+ # @param (see #create)
40
+ # @yield (see #create)
41
+ # @return (see #create)
42
+ def build(**attributes, &block)
43
+ block ||= proc {}
73
44
 
74
- other.model_class == model_class
45
+ model_class.new(attributes).tap(&block).tap do |model|
46
+ event_registry.trigger(:build, model)
47
+ end
75
48
  end
76
49
 
77
- protected
78
-
79
50
  # @method model_class
80
51
  # @api private
81
52
  #
82
53
  # Model class to be initialized into a model
83
54
  #
84
55
  # @return [Class]
85
- attr_reader :model_class
86
56
 
57
+ # @method event_registry
87
58
  # @private
88
59
  #
89
60
  # Event registry
@@ -92,8 +63,6 @@ module Zyra
92
63
  # post build or creating events
93
64
  #
94
65
  # @return [Jace::Registry]
95
- def event_registry
96
- @event_registry ||= Jace::Registry.new
97
- end
66
+ attr_reader :model_class, :event_registry
98
67
  end
99
68
  end
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'sinclair'
4
3
  require 'jace'
5
4
 
6
5
  module Zyra
7
6
  module Exceptions
8
- class BuilderNotRegistered < StandardError; end
7
+ # Exception returned when a model has not been registered
8
+ # and there is an attempt to use it
9
+ class NotRegistered < StandardError; end
9
10
  end
10
11
  end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zyra
4
+ # @api private
5
+ # @author Darthjee
6
+ #
7
+ # Class responsible for finding a model in the DB
8
+ class Finder
9
+ # @param model_class [Class] Model class that does the ORM
10
+ # @param keys [Array<Symbol,String>] keys used when searching
11
+ # for the entry
12
+ # @param event_registry [Jace::Registry] event registry to handle events
13
+ def initialize(model_class, keys, event_registry:)
14
+ @model_class = model_class
15
+ @keys = [keys].flatten.map(&:to_sym)
16
+ @event_registry = event_registry
17
+ end
18
+
19
+ # Search the entry in the database
20
+ #
21
+ # The query is done using part of the expected
22
+ # attributes filtered by the configured keys}
23
+ #
24
+ # if the model is found an event is triggered
25
+ #
26
+ # @param attributes [Hash] expected model attribiutes
27
+ # @param block [Proc] block to be ran after where
28
+ # more attributes will be set
29
+ #
30
+ # @yield [Object] Instance of the model class found
31
+ #
32
+ # @return [Object] the model from the database
33
+ def find(attributes, &block)
34
+ model = find_by(attributes)
35
+ return unless model
36
+
37
+ block ||= proc {}
38
+ model.tap(&block)
39
+
40
+ event_registry.trigger(:found, model) { model }
41
+ end
42
+
43
+ protected
44
+
45
+ # @method model_class
46
+ # @api private
47
+ #
48
+ # Model class to be initialized into a model
49
+ #
50
+ # @return [Class]
51
+
52
+ # @method keys
53
+ # @api private
54
+ #
55
+ # Keys used when finding a model
56
+ #
57
+ # @return [Array<Symbol>]
58
+
59
+ # @method event_registry
60
+ # @private
61
+ #
62
+ # Event registry
63
+ #
64
+ # The event registry will contain all handlers for
65
+ # post found events
66
+ #
67
+ # @return [Jace::Registry]
68
+ attr_reader :model_class, :keys, :event_registry
69
+
70
+ # private
71
+ #
72
+ # Extracts queriable attributes
73
+ #
74
+ # The queriable attributes are taken from the expected
75
+ # attributes filtered by the given keys in the Finder
76
+ # initialization
77
+ #
78
+ # @param (see #find)
79
+ #
80
+ # @return [Hash]
81
+ def query_from(attributes)
82
+ attributes.symbolize_keys.select do |attribute, _value|
83
+ keys.include?(attribute)
84
+ end
85
+ end
86
+
87
+ # @private
88
+ #
89
+ # Search the entry in the database
90
+ #
91
+ # The query is done using part of the expected
92
+ # attributes filtered by the configured keys}
93
+ #
94
+ # @param (see #find)
95
+ #
96
+ # @return (see #find)
97
+ def find_by(attributes)
98
+ query = query_from(attributes)
99
+
100
+ model_class.find_by(**query)
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zyra
4
+ # @api private
5
+ # Class responsible for making sure a model existis
6
+ #
7
+ # First, the object searchs in he database by the keys, and
8
+ # if it fails to finds, it creates a new entry
9
+ class FinderCreator
10
+ # @param model_class [Class] Model class that does the ORM
11
+ # @param keys [Array<Symbol,String>] keys used when searching
12
+ # for the entry
13
+ def initialize(model_class, keys)
14
+ @model_class = model_class
15
+ @keys = [keys].flatten.map(&:to_sym)
16
+ end
17
+
18
+ # Ensures an entry exists in the database
19
+ #
20
+ # The query happens first by looking in the database
21
+ # for an entry using {Finder finder}
22
+ #
23
+ # The query only takes some attributes into consideration,
24
+ #
25
+ # In case no entry is found, a new one is created using all
26
+ # the given attributes
27
+ #
28
+ # @param attributes [Hash] expected attributes
29
+ # @param block [Proc] block to be ran after where more attributes
30
+ # will be set
31
+ #
32
+ # @yield [Object] Instance of the model class
33
+ #
34
+ # @return [Object] An instance of model either from
35
+ # database or recently inserted
36
+ #
37
+ # @see Zyra::Finder#find
38
+ # @see Zyra::Creator#create
39
+ def find_or_create(attributes, &block)
40
+ model = find(attributes, &block) || create(attributes, &block)
41
+
42
+ event_registry.trigger(:return, model) { model }
43
+ end
44
+
45
+ # Register a handler on a certain event
46
+ #
47
+ # Possible events are +found+, +build+, +create+
48
+ # and +return+
49
+ #
50
+ # @param event [Symbol,String] event to be watched.
51
+ # Current events are +found+, +build+, +create+ and +return+
52
+ # @param block [Proc] block to be executed when the event is called
53
+ #
54
+ # @yield [Object] the model to be returned
55
+ #
56
+ # @return [Finder] the finder itself
57
+ def on(event, &block)
58
+ tap { event_registry.register(event, &block) }
59
+ end
60
+
61
+ # Checks if another finder creator is equal to the current
62
+ #
63
+ # This is used mostly for rspec expectations
64
+ #
65
+ # @param other [Object] other object to be compared
66
+ #
67
+ # @return [TrueClass,FalseClass]
68
+ def ==(other)
69
+ return unless other.class == self.class
70
+
71
+ other.model_class == model_class &&
72
+ other.keys == keys
73
+ end
74
+
75
+ protected
76
+
77
+ # @method model_class
78
+ # @api private
79
+ #
80
+ # Model class to be initialized into a model
81
+ #
82
+ # @return [Class]
83
+
84
+ # @method keys
85
+ # @api private
86
+ #
87
+ # Keys used when finding a model
88
+ #
89
+ # @return [Array<Symbol>]
90
+ attr_reader :model_class, :keys
91
+
92
+ # @private
93
+ #
94
+ # Event registry
95
+ #
96
+ # The event registry will contain all handlers for
97
+ # post build or creating events
98
+ #
99
+ # @return [Jace::Registry]
100
+ def event_registry
101
+ @event_registry ||= Jace::Registry.new
102
+ end
103
+
104
+ # @private
105
+ #
106
+ # Returns an instance of {Finder}
107
+ #
108
+ # Finder will use the same event registry so that event
109
+ # handling and registration is centralized
110
+ #
111
+ # @return Finder
112
+ def finder
113
+ @finder ||= Finder.new(model_class, keys, event_registry: event_registry)
114
+ end
115
+
116
+ # @method find(attributes)
117
+ #
118
+ # @private
119
+ # @api private
120
+ #
121
+ # Search the entry in the database
122
+ #
123
+ # The query is done using part of the expected
124
+ # attributes filtered by the configured keys}
125
+ #
126
+ # if the model is found an event is triggered
127
+ #
128
+ # @overload find(attributes)
129
+ # @param attributes [Hash] expected model attribiutes
130
+ #
131
+ # @return [Object] the model from the database
132
+ delegate :find, to: :finder
133
+
134
+ # @method create(attributes, &block)
135
+ # @private
136
+ # @api private
137
+ #
138
+ # Creates an instance of the registered model class
139
+ #
140
+ # @overload create(attributes, &block)
141
+ # @param attributes [Hash] attributes to be set in the model
142
+ # @param block [Proc] block to be ran after where more attributes
143
+ # will be set
144
+ #
145
+ # @yield [Object] Instance of the model class
146
+ #
147
+ # @return [Object] an instance of model class
148
+ delegate :create, to: :creator
149
+
150
+ # @private
151
+ #
152
+ # Returns an instance of {Creator}
153
+ #
154
+ # Creator will use the same event registry so that event
155
+ # handling and registration is centralized
156
+ #
157
+ # @return Creator
158
+ def creator
159
+ @creator ||= Creator.new(model_class, event_registry: event_registry)
160
+ end
161
+ end
162
+ end