hexx 7.1.0 → 8.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 +4 -4
- data/.coveralls.yml +2 -0
- data/.gitignore +9 -0
- data/.metrics +5 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -63
- data/.travis.yml +5 -0
- data/.yardopts +2 -0
- data/Gemfile +3 -0
- data/Guardfile +16 -0
- data/{LICENSE.rdoc → LICENSE} +2 -2
- data/README.md +138 -0
- data/Rakefile +8 -14
- data/config/initializer.rb +5 -0
- data/config/initializers/capture.rb +19 -0
- data/config/initializers/sandbox.rb +16 -0
- data/config/initializers/sandbox/helpers.rb +38 -0
- data/config/initializers/sandbox/matchers.rb +19 -0
- data/config/metrics/STYLEGUIDE +230 -0
- data/config/metrics/cane.yml +5 -0
- data/config/metrics/churn.yml +6 -0
- data/config/metrics/flay.yml +2 -0
- data/config/metrics/metric_fu.yml +15 -0
- data/config/metrics/pippi.yml +3 -0
- data/config/metrics/reek.yml +1 -0
- data/config/metrics/roodi.yml +24 -0
- data/config/metrics/rubocop.yml +79 -0
- data/config/metrics/saikuro.yml +3 -0
- data/config/metrics/simplecov.yml +6 -0
- data/config/metrics/yardstick.yml +37 -0
- data/hexx.gemspec +24 -0
- data/lib/hexx.rb +8 -15
- data/lib/hexx/generator.rb +71 -0
- data/lib/hexx/generator/file.rb +83 -0
- data/lib/hexx/generator/folder.rb +68 -0
- data/lib/hexx/name.rb +122 -46
- data/lib/hexx/version.rb +6 -5
- data/spec/fixtures/root/_.beta +1 -0
- data/spec/fixtures/root/__omega +0 -0
- data/spec/fixtures/root/delta.erb.erb +0 -0
- data/spec/fixtures/root/gamma.rb.erb +1 -0
- data/spec/fixtures/root/subfolder/alfa.yml +0 -0
- data/spec/spec_helper.rb +5 -10
- data/spec/tests/lib/generator_spec.rb +126 -0
- data/spec/tests/lib/name_spec.rb +113 -0
- metadata +54 -168
- data/README.rdoc +0 -371
- data/lib/hexx/coercible.rb +0 -43
- data/lib/hexx/configurable.rb +0 -101
- data/lib/hexx/creators/base.rb +0 -103
- data/lib/hexx/creators/coercion.rb +0 -82
- data/lib/hexx/creators/dependency.rb +0 -87
- data/lib/hexx/creators/module_dependency.rb +0 -57
- data/lib/hexx/creators/parameter.rb +0 -40
- data/lib/hexx/dependable.rb +0 -51
- data/lib/hexx/helpers/exceptions.rb +0 -53
- data/lib/hexx/helpers/messages.rb +0 -26
- data/lib/hexx/helpers/parameters.rb +0 -47
- data/lib/hexx/helpers/validations.rb +0 -21
- data/lib/hexx/message.rb +0 -79
- data/lib/hexx/null.rb +0 -218
- data/lib/hexx/service.rb +0 -388
- data/lib/hexx/service/with_callbacks.rb +0 -104
- data/lib/hexx/service_invalid.rb +0 -73
- data/spec/hexx/coercible_spec.rb +0 -72
- data/spec/hexx/configurable_spec.rb +0 -93
- data/spec/hexx/dependable_spec.rb +0 -125
- data/spec/hexx/helpers/exceptions_spec.rb +0 -96
- data/spec/hexx/helpers/messages_spec.rb +0 -48
- data/spec/hexx/helpers/parameters_spec.rb +0 -96
- data/spec/hexx/helpers/validations_spec.rb +0 -32
- data/spec/hexx/message_spec.rb +0 -83
- data/spec/hexx/name_spec.rb +0 -80
- data/spec/hexx/null_spec.rb +0 -152
- data/spec/hexx/service_invalid_spec.rb +0 -46
- data/spec/hexx/service_spec.rb +0 -89
- data/spec/support/initializers/focus.rb +0 -5
- data/spec/support/initializers/garbage_collection.rb +0 -11
- data/spec/support/initializers/i18n.rb +0 -3
- data/spec/support/initializers/random_order.rb +0 -4
- data/spec/support/initializers/rspec.rb +0 -5
- data/spec/support/matchers/methods.rb +0 -11
metadata
CHANGED
@@ -1,192 +1,96 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hexx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 8.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kozin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: extlib
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0.9'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0.9'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: hexx-suit
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
41
|
-
|
42
|
-
name: coveralls
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0.7'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0.7'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: inch
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0.5'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0.5'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: metric_fu
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '4.11'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '4.11'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rake
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '10.3'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '10.3'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: rspec
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '3.0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '3.0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: rubocop
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - "~>"
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0.23'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - "~>"
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0.23'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: guard-rspec
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - "~>"
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '4.3'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - "~>"
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '4.3'
|
139
|
-
description: Defines domain service object and model attributes coercion.
|
40
|
+
version: '0.0'
|
41
|
+
description: Collection of scaffolders.
|
140
42
|
email: andrew.kozin@gmail.com
|
141
43
|
executables: []
|
142
44
|
extensions: []
|
143
45
|
extra_rdoc_files:
|
144
|
-
-
|
145
|
-
-
|
46
|
+
- README.md
|
47
|
+
- LICENSE
|
48
|
+
- config/metrics/STYLEGUIDE
|
146
49
|
files:
|
50
|
+
- ".coveralls.yml"
|
51
|
+
- ".gitignore"
|
52
|
+
- ".metrics"
|
53
|
+
- ".rspec"
|
147
54
|
- ".rubocop.yml"
|
148
|
-
-
|
149
|
-
-
|
55
|
+
- ".travis.yml"
|
56
|
+
- ".yardopts"
|
57
|
+
- Gemfile
|
58
|
+
- Guardfile
|
59
|
+
- LICENSE
|
60
|
+
- README.md
|
150
61
|
- Rakefile
|
62
|
+
- config/initializer.rb
|
63
|
+
- config/initializers/capture.rb
|
64
|
+
- config/initializers/sandbox.rb
|
65
|
+
- config/initializers/sandbox/helpers.rb
|
66
|
+
- config/initializers/sandbox/matchers.rb
|
67
|
+
- config/metrics/STYLEGUIDE
|
68
|
+
- config/metrics/cane.yml
|
69
|
+
- config/metrics/churn.yml
|
70
|
+
- config/metrics/flay.yml
|
71
|
+
- config/metrics/metric_fu.yml
|
72
|
+
- config/metrics/pippi.yml
|
73
|
+
- config/metrics/reek.yml
|
74
|
+
- config/metrics/roodi.yml
|
75
|
+
- config/metrics/rubocop.yml
|
76
|
+
- config/metrics/saikuro.yml
|
77
|
+
- config/metrics/simplecov.yml
|
78
|
+
- config/metrics/yardstick.yml
|
79
|
+
- hexx.gemspec
|
151
80
|
- lib/hexx.rb
|
152
|
-
- lib/hexx/
|
153
|
-
- lib/hexx/
|
154
|
-
- lib/hexx/
|
155
|
-
- lib/hexx/creators/coercion.rb
|
156
|
-
- lib/hexx/creators/dependency.rb
|
157
|
-
- lib/hexx/creators/module_dependency.rb
|
158
|
-
- lib/hexx/creators/parameter.rb
|
159
|
-
- lib/hexx/dependable.rb
|
160
|
-
- lib/hexx/helpers/exceptions.rb
|
161
|
-
- lib/hexx/helpers/messages.rb
|
162
|
-
- lib/hexx/helpers/parameters.rb
|
163
|
-
- lib/hexx/helpers/validations.rb
|
164
|
-
- lib/hexx/message.rb
|
81
|
+
- lib/hexx/generator.rb
|
82
|
+
- lib/hexx/generator/file.rb
|
83
|
+
- lib/hexx/generator/folder.rb
|
165
84
|
- lib/hexx/name.rb
|
166
|
-
- lib/hexx/null.rb
|
167
|
-
- lib/hexx/service.rb
|
168
|
-
- lib/hexx/service/with_callbacks.rb
|
169
|
-
- lib/hexx/service_invalid.rb
|
170
85
|
- lib/hexx/version.rb
|
171
|
-
- spec/
|
172
|
-
- spec/
|
173
|
-
- spec/
|
174
|
-
- spec/
|
175
|
-
- spec/
|
176
|
-
- spec/hexx/helpers/parameters_spec.rb
|
177
|
-
- spec/hexx/helpers/validations_spec.rb
|
178
|
-
- spec/hexx/message_spec.rb
|
179
|
-
- spec/hexx/name_spec.rb
|
180
|
-
- spec/hexx/null_spec.rb
|
181
|
-
- spec/hexx/service_invalid_spec.rb
|
182
|
-
- spec/hexx/service_spec.rb
|
86
|
+
- spec/fixtures/root/_.beta
|
87
|
+
- spec/fixtures/root/__omega
|
88
|
+
- spec/fixtures/root/delta.erb.erb
|
89
|
+
- spec/fixtures/root/gamma.rb.erb
|
90
|
+
- spec/fixtures/root/subfolder/alfa.yml
|
183
91
|
- spec/spec_helper.rb
|
184
|
-
- spec/
|
185
|
-
- spec/
|
186
|
-
- spec/support/initializers/i18n.rb
|
187
|
-
- spec/support/initializers/random_order.rb
|
188
|
-
- spec/support/initializers/rspec.rb
|
189
|
-
- spec/support/matchers/methods.rb
|
92
|
+
- spec/tests/lib/generator_spec.rb
|
93
|
+
- spec/tests/lib/name_spec.rb
|
190
94
|
homepage: https://github.com/nepalez/hexx
|
191
95
|
licenses:
|
192
96
|
- MIT
|
@@ -197,7 +101,7 @@ require_paths:
|
|
197
101
|
- lib
|
198
102
|
required_ruby_version: !ruby/object:Gem::Requirement
|
199
103
|
requirements:
|
200
|
-
- - "
|
104
|
+
- - ">="
|
201
105
|
- !ruby/object:Gem::Version
|
202
106
|
version: '2.1'
|
203
107
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
@@ -210,27 +114,9 @@ rubyforge_project:
|
|
210
114
|
rubygems_version: 2.2.2
|
211
115
|
signing_key:
|
212
116
|
specification_version: 4
|
213
|
-
summary:
|
117
|
+
summary: Collection of scaffolders for projects that follow the hexagonal architecture.
|
214
118
|
test_files:
|
215
119
|
- spec/spec_helper.rb
|
216
|
-
- spec/
|
217
|
-
- spec/
|
218
|
-
- spec/hexx/null_spec.rb
|
219
|
-
- spec/hexx/helpers/parameters_spec.rb
|
220
|
-
- spec/hexx/helpers/messages_spec.rb
|
221
|
-
- spec/hexx/helpers/validations_spec.rb
|
222
|
-
- spec/hexx/helpers/exceptions_spec.rb
|
223
|
-
- spec/hexx/service_invalid_spec.rb
|
224
|
-
- spec/hexx/coercible_spec.rb
|
225
|
-
- spec/hexx/dependable_spec.rb
|
226
|
-
- spec/hexx/name_spec.rb
|
227
|
-
- spec/hexx/configurable_spec.rb
|
228
|
-
- spec/support/matchers/methods.rb
|
229
|
-
- spec/support/initializers/garbage_collection.rb
|
230
|
-
- spec/support/initializers/i18n.rb
|
231
|
-
- spec/support/initializers/focus.rb
|
232
|
-
- spec/support/initializers/random_order.rb
|
233
|
-
- spec/support/initializers/rspec.rb
|
234
|
-
- Rakefile
|
235
|
-
- ".rubocop.yml"
|
120
|
+
- spec/tests/lib/generator_spec.rb
|
121
|
+
- spec/tests/lib/name_spec.rb
|
236
122
|
has_rdoc:
|
data/README.rdoc
DELETED
@@ -1,371 +0,0 @@
|
|
1
|
-
= Hexx
|
2
|
-
|
3
|
-
{<img src="http://img.shields.io/gem/v/hexx.svg?style=flat" alt="Gem Version" />}[https://rubygems.org/gems/hexx]
|
4
|
-
{<img src="http://img.shields.io/travis/nepalez/hexx.svg?style=flat" alt="Bild Status" />}[https://travis-ci.org/nepalez/hexx]
|
5
|
-
{<img src="http://img.shields.io/codeclimate/github/nepalez/hexx.svg?style=flat" alt="Code Metrics" />}[https://codeclimate.com/github/nepalez/hexx]
|
6
|
-
{<img src="http://img.shields.io/gemnasium/nepalez/hexx.svg?style=flat" alt="Dependency Status" />}[https://gemnasium.com/nepalez/hexx]
|
7
|
-
{<img src="http://img.shields.io/coveralls/nepalez/hexx.svg?style=flat" alt="Coverage Status" />}[https://coveralls.io/r/nepalez/hexx]
|
8
|
-
{<img src="http://img.shields.io/badge/license-MIT-blue.svg?style=flat" alt="License" />}[https://github.com/nepalez/hexx/blob/master/LICENSE.rdoc]
|
9
|
-
|
10
|
-
The base library for domain models.
|
11
|
-
|
12
|
-
== API
|
13
|
-
|
14
|
-
Includes classes and modules as below:
|
15
|
-
<tt>Hexx::Service</tt>:: The base class for service objects.
|
16
|
-
<tt>Hexx::Message</tt>:: The message provided by service objects.
|
17
|
-
<tt>Hexx::Null</tt>:: The Null object.
|
18
|
-
<tt>Hexx::Coercible</tt>:: The module that makes model attributes coercible.
|
19
|
-
<tt>Hexx::Configurable</tt>:: The module to convert a core domain module to the
|
20
|
-
dependency injection framework.
|
21
|
-
<tt>Hexx::Dependable</tt>:: The module provides +depends_on+ class helper methodto
|
22
|
-
to implement the setter dependency injection.
|
23
|
-
|
24
|
-
The module is expected to be used in PORO domains for Ruby MRI 2.1+.
|
25
|
-
|
26
|
-
For usage in active record bases domains consider the
|
27
|
-
{ hexx-active_record }[https://github.com/nepalez/hexx-active_record]
|
28
|
-
gem extension.
|
29
|
-
|
30
|
-
== Installation
|
31
|
-
|
32
|
-
Add this line to your application's Gemfile:
|
33
|
-
|
34
|
-
gem "hexx", "~> 2.0"
|
35
|
-
|
36
|
-
And then execute:
|
37
|
-
|
38
|
-
$ bundle
|
39
|
-
|
40
|
-
Or install it yourself as:
|
41
|
-
|
42
|
-
$ gem install hexx
|
43
|
-
|
44
|
-
== Usage
|
45
|
-
|
46
|
-
=== Hexx::Configurable
|
47
|
-
|
48
|
-
Adds the +configure+ and +depends_on+ helpers to the module to convert it
|
49
|
-
to the {dependency injection container}[http://en.m.wikipedia.org/wiki/Dependency_injection].
|
50
|
-
|
51
|
-
Extend the base class of the gem and declare the module dependencies from
|
52
|
-
outer classes and modules with the +depend_on+ helper:
|
53
|
-
|
54
|
-
# lib/my_gem.rb
|
55
|
-
module MyGem
|
56
|
-
extend Hexx::Configurable
|
57
|
-
|
58
|
-
depend_on :get_item, :add_item
|
59
|
-
end
|
60
|
-
|
61
|
-
Inject the dependencies in the gem config with the +configure+ wrapper:
|
62
|
-
|
63
|
-
# config/dependencies.rb
|
64
|
-
MyGem.configure do |c|
|
65
|
-
c.get_item = OuterModule::Services::Get
|
66
|
-
c.add_item = OuterModule::Services::Add
|
67
|
-
end
|
68
|
-
|
69
|
-
Use the dependencies somewhere inside the code of the gem:
|
70
|
-
|
71
|
-
MyGem.get_item # => OuterModule::Services::Get
|
72
|
-
|
73
|
-
=== Hexx::Coercible
|
74
|
-
|
75
|
-
Adds the +attr_coerced+ class helper method to the PORO model.
|
76
|
-
|
77
|
-
Provide a value object that accepts <tt>0..1</tt> arguments.
|
78
|
-
|
79
|
-
# app/attributes/coercer.rb
|
80
|
-
class Coercer < MultiByte::Chars
|
81
|
-
def self.new(source = nil)
|
82
|
-
return unless source
|
83
|
-
end
|
84
|
-
|
85
|
-
def initialize(source)
|
86
|
-
# ...
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
Extend the model with a +Coercible+ module and declare its attributes
|
91
|
-
with the +attr_coerced+ helper.
|
92
|
-
|
93
|
-
# app/models/some_model.rb
|
94
|
-
class SomeModel
|
95
|
-
extend Hexx::Coercible
|
96
|
-
|
97
|
-
attr_coerced :name, type: Coercer
|
98
|
-
end
|
99
|
-
|
100
|
-
Both the getter and setter will return the coerced value, provided by
|
101
|
-
the +Coercer+ class.
|
102
|
-
|
103
|
-
object = SomeModel.new name: "Ivo"
|
104
|
-
object.name
|
105
|
-
# #<Coercer @wrapped_string="Ivo" >
|
106
|
-
|
107
|
-
Be careful when designing a coercer class. Its constructor should accept both
|
108
|
-
the raw value (<tt>"Ivo"</tt>) and the coerced one (<tt>#<Coercer @wrapped_string = "Ivo"></tt>).
|
109
|
-
This is needed because the coercer works twofold - it coerces both the
|
110
|
-
setter and getter. The getter coercer will take the coerced value.
|
111
|
-
|
112
|
-
This feature is added for compatibility with +ActiveRecord+ attributes
|
113
|
-
whose getters gives raw values from a database.
|
114
|
-
|
115
|
-
*Note*: The coercer from the +hexx+ gem itself won't work for +ActiveRecord+ models.
|
116
|
-
Use the +hexx-active_record+ gem instead. The gem extends the +Coercible+ model
|
117
|
-
so that the +attr_coerced+ reloads +ActiveRecord+ attributes properly.
|
118
|
-
|
119
|
-
=== Hexx::Service
|
120
|
-
|
121
|
-
Inherit services from the <tt>Hexx::Service</tt> class.
|
122
|
-
|
123
|
-
The class implements a set of patterns:
|
124
|
-
|
125
|
-
* The {Service object pattern}[http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/] used to decouple business logics from both the models and web delivery mechanism (such as +Rails+).
|
126
|
-
* The {Observer pattern}[http://reefpoints.dockyard.com/2013/08/20/design-patterns-observer-pattern.html] to follow the {Tell, don't ask}[http://martinfowler.com/bliki/TellDontAsk.html] design princible.
|
127
|
-
The pattern is implemented with the help of {wisper}[http://www.github.com/krisleech/wisper] gem by Kris Leech.
|
128
|
-
|
129
|
-
A typical service object is shown below:
|
130
|
-
|
131
|
-
# app/services/add_item.rb
|
132
|
-
require 'hexx'
|
133
|
-
class AddItem < Hexx::Service
|
134
|
-
|
135
|
-
# Whitelists parameters and defines corresponding attributes.
|
136
|
-
# For example, the #name attribute is avalable.
|
137
|
-
allow_params :name
|
138
|
-
|
139
|
-
# Defines some validation using ActiveModel::Validations helpers.
|
140
|
-
validate :name, presence: true
|
141
|
-
|
142
|
-
# Runs a service
|
143
|
-
def run
|
144
|
-
run!
|
145
|
-
rescue Found
|
146
|
-
# Publishes notification in case the item exists.
|
147
|
-
publish :found, item
|
148
|
-
rescue => err
|
149
|
-
publish :error, err.messages
|
150
|
-
else
|
151
|
-
# The notification to be published if the #run! raises nothing.
|
152
|
-
publish :added, item
|
153
|
-
end
|
154
|
-
|
155
|
-
private
|
156
|
-
|
157
|
-
attr_accessor :item
|
158
|
-
|
159
|
-
# Declares specific exceptions to be raised by the #run! method
|
160
|
-
# and processed by the #run differently.
|
161
|
-
#
|
162
|
-
# All other exceptions will be re-raised as Hexx::Service::Invalid
|
163
|
-
# and processed by publishing the :error notification.
|
164
|
-
raises :Found
|
165
|
-
|
166
|
-
# The sequence of the service steps. Any step can raise error to
|
167
|
-
# be rescued in #run with publishing a corresponding notification.
|
168
|
-
def run!
|
169
|
-
find_item
|
170
|
-
add_item
|
171
|
-
end
|
172
|
-
|
173
|
-
def find_item
|
174
|
-
# The method runs another service and listens to its notifications
|
175
|
-
# via private callback methods available to that service only.
|
176
|
-
# The callback names should start from given prefix (:on_item_).
|
177
|
-
run_service GetItem, :on_item, name: name
|
178
|
-
end
|
179
|
-
|
180
|
-
# The callback to listen to :found notification of the 'get_item' service.
|
181
|
-
def on_item_found(item, *)
|
182
|
-
@item = item
|
183
|
-
# Adds the Hexx::Message object of type "error" to the +messages+ array.
|
184
|
-
# The :not_found key will be translated in context of current service:
|
185
|
-
# {locale}.activemodule.messages.models.add_item.not_found
|
186
|
-
add_message "error", :not_found
|
187
|
-
fail Found # goes to publishing a result
|
188
|
-
end
|
189
|
-
|
190
|
-
# The callback to listen to :error notification of the 'get_item' service.
|
191
|
-
# that is expected to publish a list of error messages.
|
192
|
-
def on_item_error(*, messages)
|
193
|
-
# The helper raises Hexx::Service::Invalid exception where the messages
|
194
|
-
# are added to. The exception will be rescued by the #run method.
|
195
|
-
on_error(messages)
|
196
|
-
end
|
197
|
-
|
198
|
-
def add_item
|
199
|
-
# The escape re-raises any error as the Hexx::Service::Invalid
|
200
|
-
# with the array of Hexx::Message messages.
|
201
|
-
escape { @item = Item.create! name: name }
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
A typical usage of the service (in a Rails controller):
|
206
|
-
|
207
|
-
# app/controllers/items_controller.rb
|
208
|
-
class ItemsController < ActionController::Base
|
209
|
-
|
210
|
-
# Creates an item with given name
|
211
|
-
def create
|
212
|
-
service = AddItem.new params.allow(:name)
|
213
|
-
service.subscribe self, prefix: :on
|
214
|
-
service.run
|
215
|
-
end
|
216
|
-
|
217
|
-
# Publishes a success message
|
218
|
-
def on_created(item, messages)
|
219
|
-
@item = item
|
220
|
-
self.messages.concat messages
|
221
|
-
render "created", status: 201
|
222
|
-
end
|
223
|
-
|
224
|
-
# Responds with 304 (not changed)
|
225
|
-
def on_found(*)
|
226
|
-
render nothing: true, status: 304
|
227
|
-
end
|
228
|
-
|
229
|
-
# Publishes an error messages
|
230
|
-
def on_error(messages)
|
231
|
-
@messages = messages
|
232
|
-
render "error", status: 422
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
The controller knows nothing about the action itself. It only needs to
|
237
|
-
send the request to a corresponding service and sort out the notifications.
|
238
|
-
|
239
|
-
=== Hexx::Message
|
240
|
-
|
241
|
-
The messages published by the service has two attributes: +type+ and +text+.
|
242
|
-
|
243
|
-
message = Hexx::Message.new type: :error, text: "some error message"
|
244
|
-
message.type # => "error"
|
245
|
-
message.text # => "some error message"
|
246
|
-
|
247
|
-
Inside a service use the +add_message+ to add message to the +messages+ array:
|
248
|
-
|
249
|
-
add_message "error", "text"
|
250
|
-
messages # => [#<Hexx::Message @type="error", @text="text" >]
|
251
|
-
|
252
|
-
=== Hexx::Dependable
|
253
|
-
|
254
|
-
The module provides the +depends_on+ class helper for {setter-based dependency injection}[http://brandonhilkert.com/blog/a-ruby-refactor-exploring-dependency-injection-options/]. It allows decoupling the service from another services it uses.
|
255
|
-
|
256
|
-
Extend the service class and declare the dependencies with an optional default
|
257
|
-
implementation (see example above):
|
258
|
-
|
259
|
-
class AddItem < Hexx::Service
|
260
|
-
extend Hexx::Dependable
|
261
|
-
|
262
|
-
depends_on :get_item, default: GetItem
|
263
|
-
|
264
|
-
# ...
|
265
|
-
|
266
|
-
def find_item
|
267
|
-
run_service get_item, :on_item, name: name
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
|
-
Now the dependency can be injected afterwards:
|
272
|
-
|
273
|
-
# The default implementation
|
274
|
-
service = AddItem.new
|
275
|
-
service.get_item # => GetItem
|
276
|
-
|
277
|
-
# Change it to other implementation
|
278
|
-
service.get_item = FindItem
|
279
|
-
service.get_item # => FindItem
|
280
|
-
|
281
|
-
# Reset it to default by assigning +nil+
|
282
|
-
service.get_item = nil
|
283
|
-
service.get_item # => GetItem
|
284
|
-
|
285
|
-
It is possible to test a service in isolation from its dependencies.
|
286
|
-
|
287
|
-
# spec/services/my_service_spec.rb
|
288
|
-
describe AddService do
|
289
|
-
|
290
|
-
describe "#run" do
|
291
|
-
|
292
|
-
# Mock a service objects to publish expected notifications
|
293
|
-
let(:object) { Hexx::Service }
|
294
|
-
before { allow(object).to receive(:run) { publish :not_found } }
|
295
|
-
|
296
|
-
# Inject a class dependency
|
297
|
-
before { service.get_item = class_double "Hexx::Service", new: object }
|
298
|
-
|
299
|
-
# ...
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
=== Hexx::Name
|
304
|
-
|
305
|
-
The module provides the base class for name constructors for various instances.
|
306
|
-
|
307
|
-
It declares helpers:
|
308
|
-
|
309
|
-
* +object+:: the attribute for the object to be named
|
310
|
-
* +locale+:: the locale to name the object in
|
311
|
-
* +scope+:: the current translation scope
|
312
|
-
* +t(value, options):: the translator of the value in current scope and locale
|
313
|
-
|
314
|
-
Inherit the class and reload its <tt>#for</tt> instance method:
|
315
|
-
|
316
|
-
module Names
|
317
|
-
class Hash < Hexx::Name
|
318
|
-
def for
|
319
|
-
user ? t(:user, value: user) : t(:empty)
|
320
|
-
end
|
321
|
-
|
322
|
-
def user
|
323
|
-
value = object[:user]
|
324
|
-
value ? value.upcase : nil
|
325
|
-
end
|
326
|
-
end
|
327
|
-
end
|
328
|
-
|
329
|
-
Add the necessary translations:
|
330
|
-
|
331
|
-
# config/locales/ru.yml
|
332
|
-
ru:
|
333
|
-
activemodel:
|
334
|
-
names/hash:
|
335
|
-
user: "чувак %{value}"
|
336
|
-
empty: "н/д"
|
337
|
-
|
338
|
-
# config/locales/en.yml
|
339
|
-
en:
|
340
|
-
activemodel:
|
341
|
-
names/hash:
|
342
|
-
user: "dude %{value}"
|
343
|
-
empty: "-"
|
344
|
-
|
345
|
-
Then use its <tt>for</tt> class method to construct names:
|
346
|
-
|
347
|
-
Names::Hash.for { user: "Ivan" }, locale: :en
|
348
|
-
# => "dude IVAN"
|
349
|
-
|
350
|
-
Names::Hash.for { user: nil }, locale: :ru
|
351
|
-
# => "н/д"
|
352
|
-
|
353
|
-
=== Hexx::Null
|
354
|
-
|
355
|
-
The class implements the {Null object}[http://robots.thoughtbot.com/rails-refactoring-example-introduce-null-object] pattern. The object:
|
356
|
-
|
357
|
-
* responds like +nil+ to <tt><=></tt>, +eq?+, +nil?+, +false?+, +true?+, +to_s+,
|
358
|
-
+to_i+, +to_f+, +to_c+, +to_r+, +to_nil+
|
359
|
-
* responds with +self+ to any other method call
|
360
|
-
|
361
|
-
Providing {this problem}[http://devblog.avdi.org/2011/05/30/null-objects-and-falsiness/], use double negation in logical expressions:
|
362
|
-
|
363
|
-
# Though:
|
364
|
-
Hexx::Null && true # => true
|
365
|
-
|
366
|
-
# But:
|
367
|
-
!!Hexx::Null && true # => false
|
368
|
-
|
369
|
-
== License
|
370
|
-
|
371
|
-
The project is distributed under the {MIT LICENSE}[LICENSE.rdoc].
|