zyra 0.0.1 → 1.1.0

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
  SHA256:
3
- metadata.gz: 00f7455045c5d24031d971b23b6e4aacea3e256de330600fd03993798c447b70
4
- data.tar.gz: ab6f1d457d198075c2c41040cfeced8417f003c2ead58f0ac14747e8dddb08b4
3
+ metadata.gz: 62a10b511a268b79401186b32fb0c25fe60cfbe062770f8d6de2d97a6dfee4ea
4
+ data.tar.gz: 9f5a45fc0216b1e65a7d2f5482a05087ef78787accf8c5e940bf26794e5ca7bb
5
5
  SHA512:
6
- metadata.gz: fb9d2ef90e2ab27699c3dbb97b24a651e8341e6064eeb1a7e9497775039f3fc551c2f1f513b7bd44e301b63ef18c1d8fe556cd7c01ff284e71699cab6f3b3e02
7
- data.tar.gz: 61ac5329ed5bc9f015415bca09336be77580a9eb746d4f40bf88bee4696bb5893257ea91912dc3e3e318436a01952c6e1738566775971f5471a39f39d35fd4ba
6
+ metadata.gz: 0c63b3d56aec07eacdc683fb8c8084ddb1a5f8c45011bcd8f85ce43a08df85c7d412482256075539038b266d7678dfe36a019dd36267402b8bc625ec4c821a71
7
+ data.tar.gz: bc6e5d3e3a3d3695716b048c40ea29bfeb43e62f3ffd192fb94f5887526acba84b28dcabaed422d1dd9c9e8caaa9a4b5d51528ac0504a5146b1cb79b8816c548
data/.circleci/config.yml CHANGED
@@ -7,8 +7,12 @@ workflows:
7
7
  filters:
8
8
  tags:
9
9
  only: /.*/
10
+ - checks:
11
+ filters:
12
+ tags:
13
+ only: /.*/
10
14
  - build-and-release:
11
- requires: [test]
15
+ requires: [test, checks]
12
16
  filters:
13
17
  tags:
14
18
  only: /\d+\.\d+\.\d+/
@@ -18,7 +22,7 @@ workflows:
18
22
  jobs:
19
23
  test:
20
24
  docker:
21
- - image: darthjee/circleci_ruby_270:1.1.0
25
+ - image: darthjee/circleci_rails_gems:1.1.0
22
26
  environment:
23
27
  PROJECT: zyra
24
28
  steps:
@@ -32,12 +36,22 @@ jobs:
32
36
  - run:
33
37
  name: RSpec
34
38
  command: bundle exec rspec
35
- - run:
36
- name: Rubocop
37
- command: rubocop
38
39
  - run:
39
40
  name: Coverage Test Report
40
41
  command: cc-test-reporter after-build --exit-code $?
42
+ checks:
43
+ docker:
44
+ - image: darthjee/circleci_rails_gems:1.1.0
45
+ environment:
46
+ PROJECT: zyra
47
+ steps:
48
+ - checkout
49
+ - run:
50
+ name: Bundle Install
51
+ command: bundle install
52
+ - run:
53
+ name: Rubocop
54
+ command: rubocop
41
55
  - run:
42
56
  name: Yardstick coverage check
43
57
  command: bundle exec rake verify_measurements
@@ -52,7 +66,7 @@ jobs:
52
66
  command: check_specs
53
67
  build-and-release:
54
68
  docker:
55
- - image: darthjee/circleci_ruby_270:1.1.0
69
+ - image: darthjee/circleci_rails_gems:1.1.0
56
70
  environment:
57
71
  PROJECT: zyra
58
72
  steps:
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/Dockerfile CHANGED
@@ -1,6 +1,6 @@
1
1
  FROM darthjee/scripts:0.3.1 as scripts
2
2
 
3
- FROM darthjee/ruby_270:1.1.0 as base
3
+ FROM darthjee/rails_gems:1.1.0 as base
4
4
 
5
5
  COPY --chown=app:app ./ /home/app/app/
6
6
 
@@ -0,0 +1,7 @@
1
+ FROM darthjee/scripts:0.3.1 as scripts
2
+
3
+ FROM darthjee/circleci_rails_gems:1.1.0 as base
4
+
5
+ COPY --chown=circleci:circleci ./ /home/circleci/project/
6
+
7
+ RUN bundle install
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- Jace
1
+ Zyra
2
2
  ====
3
3
  [![Code Climate](https://codeclimate.com/github/darthjee/zyra/badges/gpa.svg)](https://codeclimate.com/github/darthjee/zyra)
4
4
  [![Test Coverage](https://codeclimate.com/github/darthjee/zyra/badges/coverage.svg)](https://codeclimate.com/github/darthjee/zyra/coverage)
@@ -9,9 +9,15 @@ Jace
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.1](https://www.rubydoc.info/gems/zyra/0.0.1)
20
+ [https://www.rubydoc.info/gems/zyra/1.1.0](https://www.rubydoc.info/gems/zyra/1.1.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
+ ```
@@ -1,2 +1,3 @@
1
1
  ignore:
2
2
  - lib/zyra/version.rb
3
+ - lib/zyra/exceptions.rb
data/config/yardstick.yml CHANGED
@@ -15,13 +15,17 @@ rules:
15
15
  exclude: []
16
16
  ExampleTag:
17
17
  enabled: true
18
- exclude: []
18
+ excludei: []
19
19
  ReturnTag:
20
20
  enabled: true
21
21
  exclude: []
22
22
  Summary::Presence:
23
23
  enabled: true
24
- exclude: []
24
+ exclude:
25
+ - Zyra::Finder#initialize
26
+ - Zyra::Creator#initialize
27
+ - Zyra::FinderCreator#initialize
28
+ - Zyra::Registry#initialize
25
29
  Summary::Length:
26
30
  enabled: true
27
31
  exclude: []
data/docker-compose.yml CHANGED
@@ -21,3 +21,14 @@ services:
21
21
  <<: *base
22
22
  depends_on: [base_build]
23
23
  command: /bin/bash -c 'rspec && yard && rake yardstick_measure && rake verify_measurements'
24
+
25
+ circleci:
26
+ <<: *base
27
+ build:
28
+ context: ./
29
+ dockerfile: Dockerfile.circleci
30
+ command: echo done
31
+ image: zyra_circleci
32
+ working_dir: /home/circleci/project
33
+ volumes:
34
+ - .:/home/circleci/project
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zyra
4
+ # @api private
5
+ # @author Darthjee
6
+ #
7
+ # Class responsible for building a model
8
+ class Creator
9
+ # @param model_class [Class] Model class to be initialized
10
+ # into a model
11
+ # @param event_registry [Jace::Registry] event registry to handle events
12
+ def initialize(model_class, event_registry:)
13
+ @model_class = model_class
14
+ @event_registry = event_registry
15
+ end
16
+
17
+ # Creates an instance of the registered model class
18
+ #
19
+ # @param attributes [Hash] attributes to be set in the model
20
+ # @param block [Proc] block to be ran after where more attributes
21
+ # will be set
22
+ #
23
+ # @yield [Object] Instance of the model class
24
+ #
25
+ # @return [Object] an instance of model class
26
+ def create(**attributes, &block)
27
+ block ||= proc {}
28
+
29
+ model = build(**attributes)
30
+
31
+ event_registry.trigger(:create, model) do
32
+ model.tap(&:save).tap(&block)
33
+ end
34
+ end
35
+
36
+ protected
37
+
38
+ # @private
39
+ # Builds an instance of the registered model class
40
+ #
41
+ # @param (see #create)
42
+ # @yield (see #create)
43
+ # @return (see #create)
44
+ def build(**attributes)
45
+ model_class.new(attributes).tap do |model|
46
+ event_registry.trigger(:build, model)
47
+ end
48
+ end
49
+
50
+ # @method model_class
51
+ # @api private
52
+ #
53
+ # Model class to be initialized into a model
54
+ #
55
+ # @return [Class]
56
+
57
+ # @method event_registry
58
+ # @private
59
+ #
60
+ # Event registry
61
+ #
62
+ # The event registry will contain all handlers for
63
+ # post build or creating events
64
+ #
65
+ # @return [Jace::Registry]
66
+ attr_reader :model_class, :event_registry
67
+ end
68
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jace'
4
+
5
+ module Zyra
6
+ module Exceptions
7
+ # Exception returned when a model has not been registered
8
+ # and there is an attempt to use it
9
+ class NotRegistered < StandardError; end
10
+ end
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