hexx 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +45 -0
  3. data/CHANGELOG.rdoc +1 -0
  4. data/LICENSE.rdoc +21 -0
  5. data/README.rdoc +235 -0
  6. data/Rakefile +31 -0
  7. data/bin/hexx +54 -0
  8. data/lib/generators/base.rb +59 -0
  9. data/lib/generators/controller/controller.rb +87 -0
  10. data/lib/generators/controller/templates/controller.erb +18 -0
  11. data/lib/generators/controller/templates/controller_action.erb +8 -0
  12. data/lib/generators/controller/templates/controller_action_spec.erb +28 -0
  13. data/lib/generators/controller/templates/controller_spec.erb +52 -0
  14. data/lib/generators/controller/templates/routing_action_spec.erb +10 -0
  15. data/lib/generators/controller/templates/routing_spec.erb +10 -0
  16. data/lib/generators/dependency/dependency.rb +34 -0
  17. data/lib/generators/dependency/templates/dependency_setting.erb +4 -0
  18. data/lib/generators/dependency/templates/dependency_setting_spec.erb +34 -0
  19. data/lib/generators/dependency/templates/module_spec.erb +22 -0
  20. data/lib/generators/domain/domain.rb +24 -0
  21. data/lib/generators/domain/templates/spec.erb +84 -0
  22. data/lib/generators/install/install.rb +115 -0
  23. data/lib/generators/install/templates/CHANGELOG.erb +1 -0
  24. data/lib/generators/install/templates/Gemfile.erb +5 -0
  25. data/lib/generators/install/templates/LICENSE.erb +21 -0
  26. data/lib/generators/install/templates/README.erb +55 -0
  27. data/lib/generators/install/templates/Rakefile.erb +34 -0
  28. data/lib/generators/install/templates/bin/rails.erb +11 -0
  29. data/lib/generators/install/templates/config/routes.erb +6 -0
  30. data/lib/generators/install/templates/gemspec.erb +29 -0
  31. data/lib/generators/install/templates/lib/engine.erb +12 -0
  32. data/lib/generators/install/templates/lib/lib.erb +10 -0
  33. data/lib/generators/install/templates/lib/version.erb +4 -0
  34. data/lib/generators/install/templates/spec/coveralls.erb +4 -0
  35. data/lib/generators/install/templates/spec/database_cleaner.erb +27 -0
  36. data/lib/generators/install/templates/spec/factory_girl.erb +6 -0
  37. data/lib/generators/install/templates/spec/factory_girl_rails.erb +1 -0
  38. data/lib/generators/install/templates/spec/focus.erb +5 -0
  39. data/lib/generators/install/templates/spec/garbage_collection.erb +11 -0
  40. data/lib/generators/install/templates/spec/i18n.erb +1 -0
  41. data/lib/generators/install/templates/spec/migrations.erb +3 -0
  42. data/lib/generators/install/templates/spec/rails.erb +6 -0
  43. data/lib/generators/install/templates/spec/random_order.erb +4 -0
  44. data/lib/generators/install/templates/spec/rspec.erb +5 -0
  45. data/lib/generators/install/templates/spec/spec_helper.erb +12 -0
  46. data/lib/generators/install/templates/spec/timecop.erb +1 -0
  47. data/lib/generators/request/request.rb +52 -0
  48. data/lib/generators/request/templates/request_spec.erb +73 -0
  49. data/lib/generators/use_case/templates/use_case.erb +29 -0
  50. data/lib/generators/use_case/templates/use_case_spec.erb +77 -0
  51. data/lib/generators/use_case/use_case.rb +31 -0
  52. data/lib/hexx.rb +2 -0
  53. data/lib/hexx/exceptions/not_found_error.rb +12 -0
  54. data/lib/hexx/exceptions/record_invalid.rb +12 -0
  55. data/lib/hexx/exceptions/runtime_error.rb +24 -0
  56. data/lib/hexx/exceptions/use_case_invalid.rb +12 -0
  57. data/lib/hexx/models.rb +82 -0
  58. data/lib/hexx/settings.rb +47 -0
  59. data/lib/hexx/use_case.rb +228 -0
  60. data/lib/hexx/version.rb +4 -0
  61. data/spec/hexx/exceptions/not_found_error_spec.rb +27 -0
  62. data/spec/hexx/exceptions/record_invalid_spec.rb +27 -0
  63. data/spec/hexx/exceptions/runtime_error_spec.rb +61 -0
  64. data/spec/hexx/exceptions/use_case_invalid_spec.rb +27 -0
  65. data/spec/hexx/models_spec.rb +64 -0
  66. data/spec/hexx/settings_spec.rb +51 -0
  67. data/spec/hexx/use_case_spec.rb +262 -0
  68. data/spec/spec_helper.rb +3 -0
  69. data/spec/support/initializers/coveralls.rb +3 -0
  70. data/spec/support/initializers/focus.rb +5 -0
  71. data/spec/support/initializers/garbage_collection.rb +11 -0
  72. data/spec/support/initializers/i18n.rb +1 -0
  73. data/spec/support/initializers/random_order.rb +4 -0
  74. data/spec/support/initializers/rspec.rb +5 -0
  75. metadata +236 -0
@@ -0,0 +1,4 @@
1
+ # Core classes to follow hexagonal domain architecture.
2
+ module Hexx
3
+ VERSION = "0.0.1"
4
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ module Hexx
4
+ describe NotFoundError do
5
+
6
+ let!(:subject) { NotFoundError }
7
+
8
+ it "inherits RuntimeError" do
9
+ expect(subject.ancestors).to be_include Hexx::RuntimeError
10
+ end
11
+
12
+ describe "#message" do
13
+
14
+ let!(:object) { double "object" }
15
+ let!(:errors) { double "errors" }
16
+ before { allow(object).to receive(:errors) { errors } }
17
+
18
+ it "customized" do
19
+ begin
20
+ fail subject.new(object)
21
+ rescue => error
22
+ expect(error.message).to eq "Not found: #{ errors.inspect }"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ module Hexx
4
+ describe RecordInvalid do
5
+
6
+ let!(:subject) { RecordInvalid }
7
+
8
+ it "inherits RuntimeError" do
9
+ expect(subject.ancestors).to be_include Hexx::RuntimeError
10
+ end
11
+
12
+ describe "#message" do
13
+
14
+ let!(:object) { double "object" }
15
+ let!(:errors) { double "errors" }
16
+ before { allow(object).to receive(:errors) { errors } }
17
+
18
+ it "customized" do
19
+ begin
20
+ fail subject.new(object)
21
+ rescue => error
22
+ expect(error.message).to eq "Invalid use case: #{ errors.inspect }"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,61 @@
1
+ require "spec_helper"
2
+
3
+ module Hexx
4
+ describe RuntimeError do
5
+
6
+ let!(:subject) { RuntimeError }
7
+ let!(:object) { double "object" }
8
+ let!(:errors) { double "errors" }
9
+ before { allow(object).to receive(:errors) { errors } }
10
+
11
+ let!(:error) { subject.new object }
12
+
13
+ it "inherits core RuntimeError" do
14
+ expect(subject.ancestors).to be_include ::RuntimeError
15
+ end
16
+
17
+ describe ".new" do
18
+
19
+ it "initializes the object attribute" do
20
+ expect(subject).to respond_to(:new).with(1).argument
21
+ end
22
+ end
23
+
24
+ describe "#object" do
25
+
26
+ it "is public" do
27
+ expect(error).to respond_to :object
28
+ end
29
+
30
+ it "initializes the #object attribute" do
31
+ expect(error.object).to eq object
32
+ end
33
+ end
34
+
35
+ describe "#errors" do
36
+
37
+ it "is public" do
38
+ expect(error).to respond_to :errors
39
+ end
40
+
41
+ it "delegated to object" do
42
+ expect(error.errors).to eq errors
43
+ end
44
+
45
+ it "set to nil unless object is set" do
46
+ expect(subject.new(nil).errors).to be_nil
47
+ end
48
+ end
49
+
50
+ describe "#message" do
51
+
52
+ it "customized" do
53
+ begin
54
+ fail error
55
+ rescue => e
56
+ expect(e.message).to eq "Runtime error: #{ errors.inspect }"
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ module Hexx
4
+ describe UseCaseInvalid do
5
+
6
+ let!(:subject) { UseCaseInvalid }
7
+
8
+ it "inherits RuntimeError" do
9
+ expect(subject.ancestors).to be_include Hexx::RuntimeError
10
+ end
11
+
12
+ describe "#message" do
13
+
14
+ let!(:object) { double "object" }
15
+ let!(:errors) { double "errors" }
16
+ before { allow(object).to receive(:errors) { errors } }
17
+
18
+ it "customized" do
19
+ begin
20
+ fail subject.new(object)
21
+ rescue => error
22
+ expect(error.message).to eq "Invalid use case: #{ errors.inspect }"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,64 @@
1
+ module Hexx
2
+ describe Models do
3
+
4
+ # ==========================================================================
5
+ # Prepare environment
6
+ # ==========================================================================
7
+
8
+ around do |example|
9
+ class TestModel; include Models; end
10
+ class TestAttribute; end
11
+ example.run
12
+ Hexx.send :remove_const, :TestAttribute
13
+ Hexx.send :remove_const, :TestModel
14
+ end
15
+
16
+ let!(:coerced_attribute) { double "coerced attribute" }
17
+ before do
18
+ allow(TestAttribute).to receive(:new) { |val| coerced_attribute if val }
19
+ end
20
+
21
+ # ==========================================================================
22
+ # Prepare variables
23
+ # ==========================================================================
24
+
25
+ let!(:subject) { TestModel }
26
+
27
+ # ==========================================================================
28
+ # Run tests
29
+ # ==========================================================================
30
+
31
+ describe "#validate!" do
32
+
33
+ let!(:object) { subject.new }
34
+
35
+ it "is public" do
36
+ expect(object).to respond_to(:validate!).with(0).arguments
37
+ end
38
+
39
+ it "returns true for valid instance" do
40
+ allow(object).to receive(:valid?) { true }
41
+ expect(object.validate!).to be_truthy
42
+ end
43
+
44
+ it "fails with Hexx::RecordInvalid for invalid instance" do
45
+ allow(object).to receive(:valid?) { false }
46
+ expect { object.validate! }.to raise_error do |error|
47
+ expect(error).to be_kind_of Hexx::RecordInvalid
48
+ expect(error.object).to eq object
49
+ end
50
+ end
51
+ end
52
+
53
+ describe ".attr_coerced" do
54
+
55
+ it "coerces an attribute with given type" do
56
+ subject.send :attr_coerced, :name, type: TestAttribute
57
+ object = subject.new
58
+ expect { object.name = "some name" }
59
+ .to change { object.name }
60
+ .from(nil).to coerced_attribute
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,51 @@
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
+ let!(: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 |c|
24
+ expect(c).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
@@ -0,0 +1,262 @@
1
+ require "spec_helper"
2
+
3
+ module Hexx
4
+ describe UseCase do
5
+
6
+ around :each do |example|
7
+ class TestCase < UseCase; end
8
+ example.run
9
+ Hexx.send :remove_const, :TestCase
10
+ end
11
+
12
+ let!(:subject) { TestCase }
13
+
14
+ # ==========================================================================
15
+ # Tests
16
+ # ==========================================================================
17
+
18
+ it "includes ActiveModel validations" do
19
+ expect(subject.ancestors).to be_include ActiveModel::Validations
20
+ end
21
+
22
+ describe ".new" do
23
+
24
+ it "accepts 0 to 1 arguments" do
25
+ expect(subject).to respond_to(:new).with(0).arguments
26
+ expect(subject).to respond_to(:new).with(1).arguments
27
+ end
28
+
29
+ it "without arguments sets #params to {}" do
30
+ use_case = subject.new
31
+ expect(use_case.send(:params)).to eq({})
32
+ end
33
+
34
+ it "with unknown key sets #params to {}" do
35
+ use_case = subject.new id: 1
36
+ expect(use_case.send(:params)).to eq({})
37
+ end
38
+
39
+ it "with non-hash argument sets #params to {}" do
40
+ use_case = subject.new 1
41
+ expect(use_case.send(:params)).to eq({})
42
+ end
43
+ end
44
+
45
+ describe ".allow_params" do
46
+
47
+ it "allows #params to accept value from arguments" do
48
+ subject.send :allow_params, :id, :name
49
+ use_case = subject.new id: 1, name: "text", wrong: :wrong
50
+ expect(use_case.send(:params)).to eq("id" => 1, "name" => "text")
51
+ end
52
+
53
+ it "stringifies keys" do
54
+ subject.send :allow_params, :"1"
55
+ use_case = subject.new 1 => 1, "1" => 2, :"1" => 3
56
+ expect(use_case.send(:params)).to eq("1" => 3)
57
+ end
58
+ end
59
+
60
+ describe "#params" do
61
+
62
+ it "is private" do
63
+ expect(subject.new).not_to respond_to :params
64
+ end
65
+ end
66
+
67
+ describe "#valid?" do
68
+
69
+ it "is private" do
70
+ expect(subject.new).not_to respond_to :valid?
71
+ end
72
+ end
73
+
74
+ describe "#invalid?" do
75
+
76
+ it "is private" do
77
+ expect(subject.new).not_to respond_to :valid?
78
+ end
79
+ end
80
+
81
+ describe "#validate!" do
82
+
83
+ let!(:use_case) { subject.new }
84
+
85
+ it "is private" do
86
+ expect(use_case).not_to respond_to :validate!
87
+ end
88
+
89
+ context "invalid use_case" do
90
+
91
+ before { allow(use_case).to receive(:valid?) { false } }
92
+
93
+ it "calls the #valid? method" do
94
+ expect(use_case).to receive :valid?
95
+ begin; use_case.send :validate!; rescue Exception; end
96
+ end
97
+
98
+ it "fails" do
99
+ expect { use_case.send :validate! }.to raise_error do |error|
100
+ expect(error).to be_kind_of UseCaseInvalid
101
+ end
102
+ end
103
+ end
104
+
105
+ context "valid use_case" do
106
+
107
+ it "passes" do
108
+ expect { use_case.send :validate! }.not_to raise_error
109
+ end
110
+
111
+ it "not changes it" do
112
+ expect { use_case.send :validate! }.not_to change { use_case }
113
+ end
114
+ end
115
+ end
116
+
117
+ describe "#run!" do
118
+
119
+ let!(:use_case) { subject.new }
120
+
121
+ it "is public" do
122
+ expect(use_case).to respond_to(:run!).with(0).arguments
123
+ end
124
+
125
+ it "raises NotImplementedError" do
126
+ expect { use_case.run! }.to raise_error do |error|
127
+ expect(error).to be_kind_of NotImplementedError
128
+ end
129
+ end
130
+ end
131
+
132
+ describe "#run" do
133
+
134
+ let!(:use_case) { subject.new }
135
+ let!(:object) { double "entity" }
136
+ let!(:errors) { { base: :invalid } }
137
+ let!(:listener) { double "listener" }
138
+
139
+ before { allow(object).to receive(:errors) { errors } }
140
+ before { use_case.subscribe listener }
141
+
142
+ it "calls the #run!" do
143
+ expect(use_case).to receive(:run!)
144
+ begin; use_case.run; rescue Exception; end
145
+ end
146
+
147
+ context "if the #run! passes" do
148
+
149
+ let!(:result) { double "result" }
150
+ before { allow(use_case).to receive(:run!) { result } }
151
+
152
+ it "returns its output" do
153
+ expect(use_case.run).to eq result
154
+ end
155
+ end
156
+
157
+ context "if the #run! raises NotFoundError" do
158
+
159
+ before do
160
+ allow(use_case).to receive(:run!) { fail NotFoundError.new object }
161
+ end
162
+
163
+ it "doesn't raise" do
164
+ expect { use_case.run }.not_to raise_error
165
+ end
166
+
167
+ it "publishes the :not_found notification" do
168
+ expect(listener).to receive(:not_found) do |messages|
169
+ expect(messages).to eq errors.values
170
+ end
171
+ use_case.run
172
+ end
173
+
174
+ it "returns nil" do
175
+ expect(use_case.run).to be_nil
176
+ end
177
+ end
178
+
179
+ context "if the #run! raises another Hexx::Runtime error" do
180
+
181
+ before do
182
+ allow(use_case).to receive(:run!) { fail RuntimeError.new object }
183
+ end
184
+
185
+ it "doesn't raise" do
186
+ expect { use_case.run }.not_to raise_error
187
+ end
188
+
189
+ it "publishes the :error notification" do
190
+ expect(listener).to receive(:error) do |messages|
191
+ expect(messages).to eq errors.values
192
+ end
193
+ use_case.run
194
+ end
195
+
196
+ it "returns nil" do
197
+ expect(use_case.run).to be_nil
198
+ end
199
+ end
200
+
201
+ context "if the #run! raises core StandardError" do
202
+
203
+ before do
204
+ allow(use_case).to receive(:run!) { fail ::StandardError }
205
+ end
206
+
207
+ it "doesn't raise" do
208
+ expect { use_case.run }.not_to raise_error
209
+ end
210
+
211
+ it "publishes the :error notification" do
212
+ expect(listener).to receive(:error) do |arg|
213
+ expect(arg).to eq ["StandardError"]
214
+ end
215
+ use_case.run
216
+ end
217
+
218
+ it "returns nil" do
219
+ expect(use_case.run).to be_nil
220
+ end
221
+ end
222
+
223
+ context "if the #run! raises non-runtime error" do
224
+
225
+ before do
226
+ allow(use_case).to receive(:run!) { fail Exception }
227
+ end
228
+
229
+ it "re-raises the error" do
230
+ expect { use_case.run }.to raise_error do |error|
231
+ expect(error.inspect).to eq Exception.new.inspect
232
+ end
233
+ end
234
+ end
235
+ end
236
+
237
+ describe "#subscribe" do
238
+
239
+ let!(:use_case) { subject.new }
240
+ let!(:listener) { double "listener" }
241
+ let!(:messages) { double "messages" }
242
+
243
+ before do
244
+ allow(use_case)
245
+ .to receive(:run!) { use_case.send :publish, :ok, messages }
246
+ end
247
+
248
+ it "is public" do
249
+ expect(use_case).to respond_to(:subscribe).with(1).argument
250
+ expect(use_case).to respond_to(:subscribe).with(2).arguments
251
+ end
252
+
253
+ it "subscribes a listener to use_case notifications" do
254
+ use_case.subscribe listener
255
+ expect(listener).to receive(:ok) do |messages|
256
+ expect(messages).to eq messages
257
+ end
258
+ use_case.run!
259
+ end
260
+ end
261
+ end
262
+ end