hexx 1.1.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -1
  3. data/README.rdoc +77 -181
  4. data/Rakefile +7 -21
  5. data/lib/hexx/models/base_coercer.rb +36 -0
  6. data/lib/hexx/models.rb +12 -57
  7. data/lib/hexx/service/invalid.rb +48 -0
  8. data/lib/hexx/service/message.rb +57 -0
  9. data/lib/hexx/service/messages.rb +34 -0
  10. data/lib/hexx/service/parameters.rb +45 -0
  11. data/lib/hexx/service/transactions.rb +30 -0
  12. data/lib/hexx/service/validations.rb +18 -0
  13. data/lib/hexx/service.rb +21 -0
  14. data/lib/hexx/version.rb +2 -2
  15. data/lib/hexx.rb +8 -2
  16. data/spec/hexx/models_spec.rb +6 -9
  17. data/spec/hexx/service/invalid_spec.rb +51 -0
  18. data/spec/hexx/service/message_spec.rb +99 -0
  19. data/spec/hexx/service_spec.rb +183 -0
  20. data/spec/{support/initializers → initializers}/coveralls.rb +0 -0
  21. data/spec/{support/initializers → initializers}/focus.rb +0 -0
  22. data/spec/{support/initializers → initializers}/garbage_collection.rb +0 -0
  23. data/spec/{support/initializers → initializers}/i18n.rb +2 -0
  24. data/spec/{support/initializers → initializers}/random_order.rb +0 -0
  25. data/spec/{support/initializers → initializers}/rspec.rb +0 -0
  26. data/spec/spec_helper.rb +3 -5
  27. metadata +31 -117
  28. data/CHANGELOG.rdoc +0 -12
  29. data/bin/hexx +0 -54
  30. data/lib/generators/base.rb +0 -59
  31. data/lib/generators/controller/controller.rb +0 -114
  32. data/lib/generators/controller/templates/controller.erb +0 -10
  33. data/lib/generators/controller/templates/controller_action.erb +0 -7
  34. data/lib/generators/controller/templates/controller_action_spec.erb +0 -21
  35. data/lib/generators/controller/templates/controller_spec.erb +0 -20
  36. data/lib/generators/controller/templates/responder_controller.erb +0 -40
  37. data/lib/generators/controller/templates/responder_controller_spec.erb +0 -65
  38. data/lib/generators/controller/templates/routing_action_spec.erb +0 -13
  39. data/lib/generators/controller/templates/routing_spec.erb +0 -11
  40. data/lib/generators/controller/templates/views_errors.erb +0 -3
  41. data/lib/generators/controller/templates/views_messages.erb +0 -3
  42. data/lib/generators/dependency/dependency.rb +0 -50
  43. data/lib/generators/dependency/templates/dependency_setting.erb +0 -4
  44. data/lib/generators/dependency/templates/dependency_setting_spec.erb +0 -39
  45. data/lib/generators/dependency/templates/initializer.erb +0 -4
  46. data/lib/generators/dependency/templates/initializer_setting.erb +0 -4
  47. data/lib/generators/dependency/templates/module_spec.erb +0 -22
  48. data/lib/generators/domain/domain.rb +0 -24
  49. data/lib/generators/domain/templates/spec.erb +0 -84
  50. data/lib/generators/install/install.rb +0 -133
  51. data/lib/generators/install/templates/bin/rails.erb +0 -11
  52. data/lib/generators/install/templates/config/routes.erb +0 -6
  53. data/lib/generators/install/templates/json_schemas/error.erb +0 -14
  54. data/lib/generators/install/templates/json_schemas/get_errors.erb +0 -18
  55. data/lib/generators/install/templates/json_schemas/success.erb +0 -14
  56. data/lib/generators/install/templates/lib/engine.erb +0 -12
  57. data/lib/generators/install/templates/lib/lib.erb +0 -10
  58. data/lib/generators/install/templates/lib/task.erb +0 -60
  59. data/lib/generators/install/templates/lib/version.erb +0 -4
  60. data/lib/generators/install/templates/matchers/controllers.erb +0 -14
  61. data/lib/generators/install/templates/matchers/json_schema.erb +0 -10
  62. data/lib/generators/install/templates/root/Gemfile.erb +0 -9
  63. data/lib/generators/install/templates/root/Guardfile.erb +0 -14
  64. data/lib/generators/install/templates/root/LICENSE.erb +0 -21
  65. data/lib/generators/install/templates/root/README.erb +0 -68
  66. data/lib/generators/install/templates/root/Rakefile.erb +0 -45
  67. data/lib/generators/install/templates/root/coveralls.erb +0 -1
  68. data/lib/generators/install/templates/root/gemspec.erb +0 -33
  69. data/lib/generators/install/templates/root/gitignore.erb +0 -28
  70. data/lib/generators/install/templates/root/rspec.erb +0 -1
  71. data/lib/generators/install/templates/root/rubocop.erb +0 -65
  72. data/lib/generators/install/templates/root/travis.erb +0 -3
  73. data/lib/generators/install/templates/spec/caching.erb +0 -12
  74. data/lib/generators/install/templates/spec/coveralls.erb +0 -4
  75. data/lib/generators/install/templates/spec/database_cleaner.erb +0 -28
  76. data/lib/generators/install/templates/spec/factory_girl_rails.erb +0 -5
  77. data/lib/generators/install/templates/spec/focus.erb +0 -5
  78. data/lib/generators/install/templates/spec/garbage_collection.erb +0 -11
  79. data/lib/generators/install/templates/spec/i18n.erb +0 -1
  80. data/lib/generators/install/templates/spec/migrations.erb +0 -3
  81. data/lib/generators/install/templates/spec/rails.erb +0 -6
  82. data/lib/generators/install/templates/spec/random_order.erb +0 -4
  83. data/lib/generators/install/templates/spec/rspec.erb +0 -10
  84. data/lib/generators/install/templates/spec/spec_helper.erb +0 -9
  85. data/lib/generators/install/templates/spec/timecop.erb +0 -1
  86. data/lib/generators/request/request.rb +0 -52
  87. data/lib/generators/request/templates/request_spec.erb +0 -66
  88. data/lib/generators/use_case/templates/use_case.erb +0 -54
  89. data/lib/generators/use_case/templates/use_case_spec.erb +0 -74
  90. data/lib/generators/use_case/use_case.rb +0 -31
  91. data/lib/hexx/exceptions/not_found_error.rb +0 -18
  92. data/lib/hexx/exceptions/runtime_error.rb +0 -27
  93. data/lib/hexx/exceptions/use_case_invalid.rb +0 -18
  94. data/lib/hexx/message.rb +0 -20
  95. data/lib/hexx/settings.rb +0 -47
  96. data/lib/hexx/use_case.rb +0 -256
  97. data/spec/hexx/exceptions/not_found_error_spec.rb +0 -21
  98. data/spec/hexx/exceptions/runtime_error_spec.rb +0 -43
  99. data/spec/hexx/exceptions/use_case_invalid_spec.rb +0 -21
  100. data/spec/hexx/message_spec.rb +0 -31
  101. data/spec/hexx/settings_spec.rb +0 -51
  102. data/spec/hexx/use_case_spec.rb +0 -274
  103. data/spec/support/exception_matchers.rb +0 -7
data/lib/hexx/settings.rb DELETED
@@ -1,47 +0,0 @@
1
- require "active_support"
2
-
3
- module Hexx
4
-
5
- # Storage for dependencies.
6
- #
7
- # Include it to your domain module and declare necessary dependencies.
8
- #
9
- # module MyProject
10
- # include Hexx::Settigns
11
- # class << self
12
- #
13
- # depends_on :some_class
14
- # end
15
- # end
16
- #
17
- # Then you can add a setting:
18
- #
19
- # # config/initializers/my_project.rb
20
- # MyProject.configure do |c|
21
- # c.some_class_name = "ExternalModule::SomeClass"
22
- # end
23
- #
24
- # And use it in a code:
25
- #
26
- # MyProject.some_class # => ExternalModule::SomeClass
27
- #
28
- module Settings
29
- extend ActiveSupport::Concern
30
-
31
- # Settings helpers
32
- module ClassMethods
33
-
34
- def configure(&block)
35
- block.call(self) if block_given?
36
- end
37
-
38
- def depends_on(name)
39
- cattr_accessor "#{ name }_name"
40
- define_singleton_method name do
41
- const = send "#{ name }_name"
42
- const ? Kernel.const_get(const) : nil
43
- end
44
- end
45
- end
46
- end
47
- end
data/lib/hexx/use_case.rb DELETED
@@ -1,256 +0,0 @@
1
- require "active_model"
2
- require "wisper"
3
-
4
- module Hexx
5
-
6
- # = About
7
- #
8
- # Use cases are a core part of a domain. They implement case-specific business
9
- # rules (unlike Entities) and named as an imperative (_Add_Doc_, _Get_Doc_).
10
- #
11
- # Typical use case provides 5 methods:
12
- #
13
- # +new+:: class method that initializes use case instance.
14
- # +subscribe+:: subscribes listeners for the use case notifications.
15
- # +run+:: implements the use case.
16
- # +run!+:: raises exceptions in case of errors.
17
- # +errors+:: collects use case errors.
18
- #
19
- # The +run+ method returns a corresponding Value object, and notifies
20
- # subscribers about the results (following The Observer Pattern).
21
- #
22
- # = Usage
23
- #
24
- # Inherit a use case from the <tt>Hexx::UseCase</tt> class:
25
- #
26
- # # app/my_domain/use_cases/do_something.rb
27
- # require "hexx"
28
- #
29
- # module MyDomain
30
- # class DoSomething < Hexx::UseCase
31
- # end
32
- # end
33
- #
34
- # Then add a <tt>run!</tt> instance method to the Use Case.
35
- #
36
- # class DoSomething < Hexx::UseCase
37
- #
38
- # def run!
39
- # validate!
40
- # # do something
41
- # end
42
- # end
43
- #
44
- # The +run+ (without a bang) method is defined by default (see below). If
45
- # you need catching some exceptions specifically, do it in your <tt>run!</tt>
46
- # method.
47
- #
48
- # Unless the <tt>run!</tt> method defined, calling the +run+ raises
49
- # the <tt>NotImplementedError</tt>.
50
- #
51
- # == Allow params
52
- #
53
- # Use case constructor takes one argument with a parameters hash.
54
- #
55
- # use_case = DoSomething.new id: 1, name: "name"
56
- #
57
- # This sets the private argument +params+ to be blank hash.
58
- #
59
- # use_case.send :params # => {}
60
- #
61
- # For options to be assigned to +params+, their keys should be whitelisted:
62
- #
63
- # class DoSomething < Hexx::UseCase
64
- #
65
- # allow_params :id, :name
66
- # end
67
- #
68
- # This will allow assigning values. Note that all the keys are stringified:
69
- #
70
- # use_case = DoSomething.new id: 1, name: "name", wrong_key: :value
71
- # use_case.send :params # => { "id" => 1, "name" => "name" }
72
- #
73
- # == Validations
74
- #
75
- # You can use ActiveRecord validations.
76
- #
77
- # Be careful! Both the <tt>valid?</tt>, and <tt>invalid?</tt> are private.
78
- # It is expected validations to be used implicitly in a course of use case
79
- # running.
80
- #
81
- # To do this a private method <tt>validate!</tt> is available. It raises the
82
- # <tt>Hexx::UseCaseInvalid</tt> exception in case of validation fails.
83
- #
84
- # Note the <tt>validate!</tt> private method call from the <tt>run!</tt>
85
- # method in the example above.
86
- #
87
- # == Running a use case
88
- #
89
- # The <tt>run</tt> method is defined in a base class. This method
90
- # catches some exceptions and publishes corresponding notifications:
91
- #
92
- # <tt>Hexx::NotFoundError</tt>:: publishes the <tt>not_found(messages)</tt>;
93
- # <tt>Hexx::UseCaseInvalid</tt>:: publishes the <tt>error(messages)</tt>;
94
- # <tt>Hexx::EntityInvalid</tt>:: publishes the <tt>error(messages)</tt>;
95
- # <tt>StandardError</tt>:: any other runtume exception.
96
- #
97
- # == Notifications publishing
98
- #
99
- # A use case is expected to publish notifications for its subscribers.
100
- #
101
- # class DoSomething < Hexx::UseCase
102
- #
103
- # def run!
104
- # validate!
105
- # # do something (raise in case of any error)
106
- # publish :done, result
107
- # return result
108
- # end
109
- # end
110
- #
111
- # This will call a +done+ method of any subscriber. For details see the
112
- # {wisper gem documentation}[https://github.com/krisleech/wisper].
113
- #
114
- # == Calling a use case
115
- #
116
- # Use cases can be called in two styles:
117
- #
118
- # === Observer Pattern style (main usage)
119
- #
120
- # From a controller you can call a use case:
121
- #
122
- # # app/controllers/my_controller.rb
123
- # class MyController < ActionController::Base
124
- #
125
- # def my_action
126
- # # initialize a use case
127
- # use_case = DoSomething.new params
128
- # # subscribe both controller (in a presenter role) and other services
129
- # # such as mailers etc. to receive notifications.
130
- # use_case.subscribe self
131
- # use_case.subscribe MyMailer.new
132
- # # run a use_case
133
- # use_case.run
134
- # end
135
- #
136
- # # the method will be called by <tt>use_case.run</tt> in case of
137
- # # success (see the Notification publishing example above).
138
- # def done(result)
139
- # # return a response 200 to the user
140
- # end
141
- #
142
- # # the method will be called by <tt>use_case.run</tt> in case of
143
- # # NotFoundError raised.
144
- # def not_found(options = {})
145
- # # return a response 404 to the user
146
- # end
147
- #
148
- # # this method will be called by use_case in case of any error
149
- # def error(messages = [])
150
- # # return a response 400 to the user
151
- # end
152
- # end
153
- #
154
- # === Procedural style
155
- #
156
- # When you use a case from another case it can be useful to get value directly
157
- # without a subscription.
158
- #
159
- # use_case = DoSomething.new params
160
- # result = use_case.run
161
- #
162
- # The +run+ method returns nil in case of any error.
163
- #
164
- # = Dependencies notes
165
- #
166
- # Use cases depends on:
167
- #
168
- # * *Entities* and their *Repositories*;
169
- # * *Values* as an interfaces to external services (controllers, mailers etc.)
170
- #
171
- # Use cases should not depend from external services outside of the domain
172
- # model: controllers, mailers, databases etc.
173
- #
174
- class UseCase
175
- include ActiveModel::Validations, Wisper::Publisher
176
-
177
- class << self
178
-
179
- def allow_params(*keys)
180
- @params = keys.map(&:to_s)
181
- end
182
-
183
- private
184
-
185
- def params
186
- @params ||= []
187
- end
188
- end
189
-
190
- def initialize(options = {})
191
- if options.is_a? Hash
192
- @params = options.stringify_keys.slice(*self.class.send(:params))
193
- else
194
- @params = {}
195
- end
196
- end
197
-
198
- # Runs a case and raises an exceptions.
199
- #
200
- # Expected to be called from another use cases. For example, in the case
201
- # below calling a <tt>GetItem#run!</tt> will raise an exception if item
202
- # not found. Further on the exception will be catched in
203
- # <tt>DeleteItem#run</tt> method as its own.
204
- #
205
- # class DeleteItem < Hexx::UseCase
206
- #
207
- # allow_params :id
208
- #
209
- # def run!
210
- # item = GetItem.new(params).run!
211
- # item.delete!
212
- # end
213
- # end
214
- #
215
- def run!
216
- fail(NotImplementedError.new "#{ self.class.name }#run! not implemented")
217
- end
218
-
219
- # Runs a case and works out exceptions with sending corresponding
220
- # notifications to listeners.
221
- #
222
- # Expected to be called from a controller action.
223
- #
224
- def run
225
- run!
226
- rescue Hexx::NotFoundError => error
227
- finish_with :not_found, error.messages
228
- rescue Hexx::RuntimeError => error
229
- finish_with :error, error.messages
230
- rescue StandardError => error
231
- finish_with :error, [error.message]
232
- end
233
-
234
- private :valid?, :invalid?
235
-
236
- private
237
-
238
- attr_reader :params
239
-
240
- def validate!
241
- return if valid?
242
- fail UseCaseInvalid.new(self)
243
- end
244
-
245
- def finish_with(name, errors)
246
- publish name, errors.map { |text| Message.new type: :error, text: text }
247
- nil
248
- end
249
-
250
- def t(key, options = {})
251
- return key unless key.is_a? Symbol
252
- scope = %w(activemodel messages models) << self.class.name.underscore
253
- I18n.t key, options.merge(scope: scope)
254
- end
255
- end
256
- end
@@ -1,21 +0,0 @@
1
- require "spec_helper"
2
- require "support/exception_matchers"
3
-
4
- module Hexx
5
- describe NotFoundError do
6
-
7
- subject { NotFoundError }
8
-
9
- it "inherits RuntimeError" do
10
- expect(subject).to inherit Hexx::RuntimeError
11
- end
12
-
13
- it "has customized message" do
14
- use_case = Hexx::UseCase.new
15
- allow(use_case)
16
- .to receive_message_chain(:errors, :messages, :values)
17
- .and_return %w(one two)
18
- expect(subject.new(use_case).message).to eq "Not found: one; two"
19
- end
20
- end
21
- end
@@ -1,43 +0,0 @@
1
- require "spec_helper"
2
- require "support/exception_matchers"
3
-
4
- module Hexx
5
- describe RuntimeError do
6
-
7
- subject { RuntimeError }
8
- let(:use_case) { Hexx::UseCase.new }
9
-
10
- it "inherits core RuntimeError" do
11
- expect(subject).to inherit ::RuntimeError
12
- end
13
-
14
- describe ".new" do
15
-
16
- it "requires Hexx::UseCase as an argument" do
17
- expect { subject.new use_case }.not_to raise_error
18
- expect { subject.new "" }.to raise_error
19
- expect { subject.new }.to raise_error
20
- end
21
- end
22
-
23
- describe "#messages" do
24
-
25
- it "returns use case's error messages" do
26
- allow(use_case)
27
- .to receive_message_chain(:errors, :messages)
28
- .and_return(argument: [:error])
29
- expect(subject.new(use_case).messages).to eq [:error]
30
- end
31
- end
32
-
33
- describe "#message" do
34
-
35
- let!(:error) { subject.new use_case }
36
- before { allow(error).to receive(:messages).and_return %w(one two) }
37
-
38
- it "returns a proper text" do
39
- expect(error.message).to eq "Runtime error: one; two"
40
- end
41
- end
42
- end
43
- end
@@ -1,21 +0,0 @@
1
- require "spec_helper"
2
- require "support/exception_matchers"
3
-
4
- module Hexx
5
- describe UseCaseInvalid do
6
-
7
- subject { UseCaseInvalid }
8
-
9
- it "inherits RuntimeError" do
10
- expect(subject).to inherit Hexx::RuntimeError
11
- end
12
-
13
- it "has customized message" do
14
- use_case = Hexx::UseCase.new
15
- allow(use_case)
16
- .to receive_message_chain(:errors, :messages, :values)
17
- .and_return %w(one two)
18
- expect(subject.new(use_case).message).to eq "Use case invalid: one; two"
19
- end
20
- end
21
- end
@@ -1,31 +0,0 @@
1
- module Hexx
2
- describe Message do
3
-
4
- let!(:message) { Message.new type: "info", text: "" }
5
-
6
- describe ".new" do
7
-
8
- it "requires type" do
9
- expect { Message.new text: "" }.to raise_error
10
- end
11
-
12
- it "requires text" do
13
- expect { Message.new type: "" }.to raise_error
14
- end
15
- end
16
-
17
- describe "#type=" do
18
-
19
- it "sets the type" do
20
- expect { message.type = :error }.to change { message.type }.to "error"
21
- end
22
- end
23
-
24
- describe "#text=" do
25
-
26
- it "sets the text" do
27
- expect { message.text = "Text" }.to change { message.text }.to "Text"
28
- end
29
- end
30
- end
31
- end
@@ -1,51 +0,0 @@
1
- require "spec_helper"
2
-
3
- module Hexx
4
- describe Settings do
5
-
6
- around do |example|
7
- module TestModule; include Settings; end
8
- class TestClass; end
9
- example.run
10
- Hexx.send :remove_const, :TestClass
11
- Hexx.send :remove_const, :TestModule
12
- end
13
-
14
- subject { TestModule }
15
-
16
- describe ".configure" do
17
-
18
- it "is public" do
19
- expect(subject).to respond_to(:configure).with(0).arguments
20
- end
21
-
22
- it "sends itself to a block" do
23
- subject.configure do |config|
24
- expect(config).to eq subject
25
- end
26
- end
27
- end
28
-
29
- describe ".depends_on" do
30
-
31
- it "is public" do
32
- expect(subject).to respond_to(:depends_on).with(1).argument
33
- end
34
-
35
- it "defines name settings accessor" do
36
- subject.depends_on :test_class
37
- expect(subject).to respond_to(:test_class_name).with(0).arguments
38
- expect(subject).to respond_to(:test_class_name=).with(1).argument
39
- expect { subject.test_class_name = "TestClass" }
40
- .to change { subject.test_class_name }.from(nil).to "TestClass"
41
- end
42
-
43
- it "defines corresponding constant reader" do
44
- subject.depends_on :test_class
45
- expect(subject).to respond_to(:test_class).with(0).arguments
46
- expect { subject.test_class_name = "Hexx::TestClass" }
47
- .to change { subject.test_class }.from(nil).to TestClass
48
- end
49
- end
50
- end
51
- end