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
@@ -0,0 +1,45 @@
1
+ module Hexx
2
+ class Service
3
+
4
+ # Contains methods to declare parameters and set their values.
5
+ module Parameters
6
+ extend ActiveSupport::Concern
7
+
8
+ # Methods to declare and allow services params.
9
+ module ClassMethods
10
+
11
+ private
12
+
13
+ def params
14
+ @params ||= []
15
+ end
16
+
17
+ def allow_params(*keys)
18
+ @params = keys.map(&:to_s)
19
+ attr_accessor(*params)
20
+ end
21
+ end
22
+
23
+ # Initializes a service object with a hash of parameters.
24
+ #
25
+ # @example
26
+ # Service.new(hash = {})
27
+ #
28
+ # Params:
29
+ # +hash+:: a hash of parameters for the service.
30
+ #
31
+ def initialize(hash = {})
32
+ extract_params_from hash
33
+ params.each { |key, value| send "#{ key }=", value }
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :params
39
+
40
+ def extract_params_from(hash)
41
+ @params = hash.stringify_keys.slice(*(self.class.send :params))
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,30 @@
1
+ require "hexx/service/invalid"
2
+
3
+ module Hexx
4
+ class Service
5
+
6
+ # Declares the <tt>##transaction</tt> private instance method.
7
+ module Transactions
8
+ include Wisper::Publisher
9
+
10
+ private
11
+
12
+ # Yields the block and publishes :error notification with
13
+ # error messages in case of any standard exception being raised.
14
+ def transaction
15
+ run_and_rescue do
16
+ validate!
17
+ yield
18
+ end
19
+ end
20
+
21
+ def run_and_rescue
22
+ yield
23
+ rescue Service::Invalid => err
24
+ publish :error, Message.from(err.service)
25
+ rescue => err
26
+ publish :error, [Message.new(type: "error", text: err.message)]
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ module Hexx
2
+ class Service
3
+
4
+ # Defines methods for active record validation.
5
+ module Validations
6
+
7
+ # Includes the <tt>ActiveModel::Validations</tt> module to the service.
8
+ def self.included(klass)
9
+ klass.include ActiveModel::Validations
10
+ end
11
+
12
+ # Runs validations and raises <tt>Service::Error</tt> if validations fail.
13
+ def validate!
14
+ fail Invalid.new(self) unless valid?
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ require "hexx/service/messages"
2
+ require "hexx/service/parameters"
3
+ require "hexx/service/validations"
4
+ require "hexx/service/transactions"
5
+
6
+ module Hexx
7
+
8
+ # Base class for service objects.
9
+ class Service
10
+ include Messages, Parameters, Transactions, Validations
11
+
12
+ # Runs the service object.
13
+ #
14
+ # The method must be defined in a specific service class,
15
+ # inherited from <tt>Hexx::Service</tt>.
16
+ #
17
+ def run
18
+ fail NotImplementedError.new "#{ self.class.name }#run not implemented."
19
+ end
20
+ end
21
+ end
data/lib/hexx/version.rb CHANGED
@@ -1,6 +1,6 @@
1
- # Core classes to follow hexagonal domain architecture.
1
+ # Namespace for the gem.
2
2
  module Hexx
3
3
 
4
4
  # Current release.
5
- VERSION = "1.1.1"
5
+ VERSION = "2.0.0"
6
6
  end
data/lib/hexx.rb CHANGED
@@ -1,2 +1,8 @@
1
- lib = File.dirname(__FILE__)
2
- Dir[File.join(lib, "hexx/**/*.rb")].each { |file| require file }
1
+ require "active_model"
2
+ require "wisper"
3
+ require "hexx/models"
4
+ require "hexx/service"
5
+
6
+ # Namespace for the gem.
7
+ module Hexx
8
+ end
@@ -1,3 +1,5 @@
1
+ require "spec_helper"
2
+
1
3
  module Hexx
2
4
  describe Models do
3
5
 
@@ -6,7 +8,7 @@ module Hexx
6
8
  # ==========================================================================
7
9
 
8
10
  around do |example|
9
- class TestModel; include Models; end
11
+ class TestModel; extend Models; end
10
12
  class TestAttribute; end
11
13
  example.run
12
14
  Hexx.send :remove_const, :TestAttribute
@@ -18,20 +20,15 @@ module Hexx
18
20
  allow(TestAttribute).to receive(:new) { |val| coerced_attribute if val }
19
21
  end
20
22
 
21
- # ==========================================================================
22
- # Prepare variables
23
- # ==========================================================================
24
-
25
- subject { TestModel }
26
- let(:object) { subject.new }
27
-
28
23
  # ==========================================================================
29
24
  # Run tests
30
25
  # ==========================================================================
31
26
 
32
27
  describe ".attr_coerced" do
33
28
 
34
- before { subject.send :attr_coerced, :name, type: TestAttribute }
29
+ subject { TestModel }
30
+ before { subject.send :attr_coerced, :name, type: TestAttribute }
31
+ let(:object) { TestModel.new }
35
32
 
36
33
  it "coerces an attribute with given type" do
37
34
  expect { object.name = "some name" }
@@ -0,0 +1,51 @@
1
+ require "spec_helper"
2
+
3
+ module Hexx
4
+ class Service
5
+ describe Invalid do
6
+
7
+ describe ".new" do
8
+
9
+ subject { Invalid }
10
+
11
+ it "fails if no arguments given" do
12
+ expect { subject.new }.to raise_error { ArgumentError }
13
+ end
14
+
15
+ it "fails unless given argument is a service" do
16
+ expect { subject.new "wrong" }.to raise_error { ArgumentError }
17
+ end
18
+
19
+ it "initializes the #service" do
20
+ expect { subject.new Service.new }.not_to raise_error
21
+ end
22
+ end
23
+
24
+ describe "#messages" do
25
+
26
+ let(:service) { Service.new }
27
+ before do
28
+ allow(service).to receive_message_chain(:errors, :values)
29
+ .and_return [%w(1 2)]
30
+ end
31
+ subject { Invalid.new(service).messages }
32
+
33
+ it "returns a list of messages" do
34
+ expect(subject.map(&:class).uniq).to eq [Service::Message]
35
+ expect(subject.map(&:type).uniq).to eq ["error"]
36
+ expect(subject.map(&:text).uniq).to eq %w(1 2)
37
+ end
38
+ end
39
+
40
+ describe "#message" do
41
+
42
+ let(:service) { Service.new }
43
+ subject { Invalid.new(service).message }
44
+
45
+ it "returns a proper message" do
46
+ expect(subject).to eq "Service invalid: #{ service.inspect }"
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,99 @@
1
+ require "spec_helper"
2
+
3
+ module Hexx
4
+ class Service
5
+ describe Message do
6
+
7
+ describe ".new" do
8
+
9
+ subject { Message }
10
+
11
+ it "requires type" do
12
+ expect { subject.new text: "" }.to raise_error
13
+ end
14
+
15
+ it "requires text" do
16
+ expect { subject.new type: "" }.to raise_error
17
+ end
18
+ end
19
+
20
+ describe ".from" do
21
+
22
+ subject { Message }
23
+ let(:service) { Service.new }
24
+ before { service.send(:errors).add :base, :text }
25
+
26
+ it "extracts error messages from a record" do
27
+ message = subject.from(service).first
28
+ expect(message).to be_kind_of Message
29
+ expect(message.type).to eq "error"
30
+ expect(message.text).to eq service.errors.values.flatten.first
31
+ end
32
+ end
33
+
34
+ describe "#type" do
35
+
36
+ subject { Message.new type: "info", text: "text" }
37
+
38
+ it "returns message type" do
39
+ expect(subject.type).to eq "info"
40
+ end
41
+ end
42
+
43
+ describe "#text" do
44
+
45
+ subject { Message.new type: "info", text: "text" }
46
+
47
+ it "returns message text" do
48
+ expect(subject.text).to eq "text"
49
+ end
50
+ end
51
+
52
+ describe "#==" do
53
+
54
+ let!(:params) { { type: "info", text: "text" } }
55
+
56
+ it "returns true if type and text of two messages are the same" do
57
+ expect(Message.new params).to eq(Message.new params)
58
+ end
59
+
60
+ it "returns false if types of two messages are different" do
61
+ expect(Message.new params)
62
+ .not_to eq(Message.new params.merge(type: "error"))
63
+ end
64
+
65
+ it "returns false if texts of two messages are different" do
66
+ expect(Message.new params)
67
+ .not_to eq(Message.new params.merge(text: "another"))
68
+ end
69
+
70
+ it "returns false when a message compares to non-message" do
71
+ expect(Message.new params).not_to eq("text")
72
+ end
73
+ end
74
+
75
+ describe "#<=>" do
76
+
77
+ let!(:aa) { Message.new type: "a", text: "a" }
78
+ let!(:ab) { Message.new type: "a", text: "b" }
79
+ let!(:ba) { Message.new type: "b", text: "a" }
80
+
81
+ it "orders messages by type" do
82
+ expect(aa < ba).to be_truthy
83
+ end
84
+
85
+ it "orders messages by text" do
86
+ expect(aa < ab).to be_truthy
87
+ end
88
+
89
+ it "orders messages first by type" do
90
+ expect(ab < ba).to be_truthy
91
+ end
92
+
93
+ it "fails when compared with non-message" do
94
+ expect { ab < "" }.to raise_error
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,183 @@
1
+ require "spec_helper"
2
+
3
+ module Hexx
4
+ describe Service do
5
+
6
+ describe "class methods" do
7
+
8
+ around :each do |example|
9
+ class TestService < Service; end
10
+ example.run
11
+ Hexx.send :remove_const, :TestService
12
+ end
13
+
14
+ subject { TestService }
15
+
16
+ it "includes ActiveModel::Validations" do
17
+ expect(subject.ancestors).to be_include ActiveModel::Validations
18
+ end
19
+
20
+ it "includes Whisper::Publisher" do
21
+ expect(subject.ancestors).to be_include Wisper::Publisher
22
+ end
23
+
24
+ describe ".allow_params" do
25
+
26
+ let(:attribute) { :name }
27
+ before { subject.send :allow_params, attribute }
28
+
29
+ it "defines attributes" do
30
+ expect(subject.instance_methods).to be_include attribute
31
+ end
32
+ end
33
+
34
+ describe ".new" do
35
+
36
+ let(:value) { "text" }
37
+ before { subject.send :allow_params, :name }
38
+ let!(:service) { subject.new name: value, wrong: "wrong" }
39
+
40
+ it "stringifies params' keys" do
41
+ expect(service.send(:params)["name"]).to eq value
42
+ expect(service.send(:params)[:name]).to be_nil
43
+ end
44
+
45
+ it "whitelistes params" do
46
+ expect(service.send(:params)["wrong"]).to be_nil
47
+ end
48
+
49
+ it "initializes attributes from params" do
50
+ expect(service.send :name).to eq value
51
+ end
52
+ end
53
+ end
54
+
55
+ describe "##validate!" do
56
+
57
+ it "passes when object is valid" do
58
+ expect { subject.validate! }.not_to raise_error
59
+ end
60
+
61
+ it "fails when object is invalid" do
62
+ allow(subject).to receive(:valid?).and_return false
63
+ expect { subject.validate! }
64
+ .to raise_error { Service::Invalid.new(subject) }
65
+ end
66
+ end
67
+
68
+ describe "##params" do
69
+
70
+ it "is defined" do
71
+ expect { subject.send :params }.not_to raise_error
72
+ end
73
+ end
74
+
75
+ describe "##t" do
76
+
77
+ let(:scope) { %w(activemodel messages models hexx/service) }
78
+ let(:traslation) { I18n.t(:text, scope: scope, name: "name") }
79
+
80
+ it "translates symbols in the service scope" do
81
+ expect(subject.send :t, :text, name: "name").to eq traslation
82
+ end
83
+
84
+ it "doesn't translate the string" do
85
+ expect(subject.send :t, "text").to eq "text"
86
+ end
87
+ end
88
+
89
+ describe "##messages" do
90
+
91
+ it "returns an array" do
92
+ expect(subject.send :messages).to be_kind_of Array
93
+ end
94
+ end
95
+
96
+ describe "##add_message" do
97
+
98
+ before { subject.send :add_message, :info, :text }
99
+ let(:message) { subject.send(:messages).first }
100
+
101
+ it "adds a new message" do
102
+ expect(message).to be_kind_of Service::Message
103
+ expect(message.type).to eq "info"
104
+ end
105
+
106
+ it "translates a symbol" do
107
+ translation = subject.send :t, :text
108
+ expect(message.text).to eq translation
109
+ end
110
+ end
111
+
112
+ describe "##transaction" do
113
+
114
+ let(:listener) { double "listener" }
115
+ before { subject.subscribe listener }
116
+
117
+ it "yields a block" do
118
+ value = "Hello!"
119
+ result = subject.send(:transaction) { value }
120
+ expect(result).to eq value
121
+ end
122
+
123
+ context "when a service invalid" do
124
+
125
+ before { allow(subject).to receive(:validate!) { fail } }
126
+
127
+ it "doesn't yield a block" do
128
+ value = "Hello!"
129
+ result = subject.send(:transaction) { value }
130
+ expect(result).not_to eq value
131
+ end
132
+
133
+ it "publishes an :error" do
134
+ expect(listener).to receive(:error)
135
+ subject.send(:transaction)
136
+ end
137
+ end
138
+
139
+ context "when a block raises Service::Invalid error" do
140
+
141
+ before { subject.send(:errors).add :base, :text }
142
+ let(:run) do
143
+ subject.send(:transaction) { fail Service::Invalid.new(subject) }
144
+ end
145
+
146
+ it "rescues" do
147
+ expect { run }.not_to raise_error
148
+ end
149
+
150
+ it "publishes an :error with service messages" do
151
+ expect(listener).to receive(:error) do |messages|
152
+ expect(messages).to eq Service::Message.from(subject)
153
+ end
154
+ run
155
+ end
156
+ end
157
+
158
+ context "when a block raises StandardError" do
159
+
160
+ let(:run) { subject.send(:transaction) { fail "text" } }
161
+
162
+ it "rescues" do
163
+ expect { run }.not_to raise_error
164
+ end
165
+
166
+ it "publishes an :error with a message" do
167
+ expect(listener).to receive(:error) do |messages|
168
+ expect(messages)
169
+ .to eq [Service::Message.new(type: "error", text: "text")]
170
+ end
171
+ run
172
+ end
173
+ end
174
+ end
175
+
176
+ describe "#run" do
177
+
178
+ it "fails with NotImplementedError" do
179
+ expect { subject.run }.to raise_error { NotImplementedError }
180
+ end
181
+ end
182
+ end
183
+ end
@@ -1 +1,3 @@
1
+ require "i18n"
2
+
1
3
  I18n.enforce_available_locales = false
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,7 @@
1
- ENV["RAILS_ENV"] ||= "test"
2
-
3
1
  root = File.dirname File.dirname(__FILE__)
4
2
 
3
+ # Support files and Rspec settings
4
+ Dir[File.join(root, "spec/initializers/*.rb")].each { |file| require file }
5
+
5
6
  # Application files
6
7
  require File.join(root, "lib/hexx.rb")
7
-
8
- # Support files and Rspec settings
9
- Dir[File.join(root, "spec/support/**/*.rb")].each { |file| require file }