command_service_object 0.4.0 → 0.5.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/CONTRIBUTING.md +92 -0
  4. data/Gemfile.lock +3 -1
  5. data/README.md +69 -39
  6. data/command_service_object.gemspec +12 -3
  7. data/lib/command_service_object/configuration.rb +14 -0
  8. data/lib/command_service_object/failure.rb +10 -0
  9. data/lib/command_service_object/helpers/controller_helper.rb +30 -0
  10. data/lib/command_service_object/helpers/failure_helper.rb +7 -0
  11. data/lib/command_service_object/helpers/model_helper.rb +49 -0
  12. data/lib/command_service_object/hooks.rb +87 -0
  13. data/lib/command_service_object/railtie.rb +13 -0
  14. data/lib/command_service_object/version.rb +1 -1
  15. data/lib/command_service_object.rb +25 -2
  16. data/lib/generators/service/command/USAGE +8 -0
  17. data/lib/generators/service/command/command_generator.rb +29 -0
  18. data/lib/generators/service/{templates → command/templates}/command.rb.erb +8 -1
  19. data/lib/generators/service/getter/getter_generator.rb +32 -0
  20. data/lib/generators/service/getter/templates/getter.rb.erb +8 -0
  21. data/lib/generators/service/install/install_generator.rb +23 -0
  22. data/lib/generators/service/install/templates/initializer.rb +19 -0
  23. data/lib/generators/service/install/templates/services/application_service.rb +35 -0
  24. data/lib/generators/service/install/templates/services/case_base.rb +13 -0
  25. data/lib/generators/service/{templates/base → install/templates/services}/service_result.rb +0 -0
  26. data/lib/generators/service/service_generator.rb +32 -96
  27. data/lib/generators/service/setter/setter_generator.rb +32 -0
  28. data/lib/generators/service/setter/templates/setter.rb.erb +12 -0
  29. data/lib/generators/service/setup/setup_generator.rb +21 -0
  30. data/lib/generators/service/test/USAGE +8 -0
  31. data/lib/generators/service/{templates → test/templates}/minitest.rb.erb +0 -0
  32. data/lib/generators/service/{templates → test/templates}/rspec.rb.erb +0 -0
  33. data/lib/generators/service/test/test_generator.rb +56 -0
  34. data/lib/generators/service/usecase/USAGE +8 -0
  35. data/lib/generators/service/{templates → usecase/templates}/usecase.rb.erb +7 -6
  36. data/lib/generators/service/usecase/usecase_generator.rb +29 -0
  37. metadata +53 -13
  38. data/lib/generators/service/templates/base/application_service.rb +0 -9
  39. data/lib/generators/service/templates/base/service_base.rb +0 -37
  40. data/lib/generators/service/templates/base/service_controller_helper.rb +0 -25
  41. data/lib/generators/service/templates/error.rb.erb +0 -9
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= service_name.classify %>::Usecases::Getters
4
+ class <%= @getter %>
5
+ def call(*args)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,23 @@
1
+ require 'rails/generators'
2
+
3
+ module Service
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('templates', __dir__)
7
+
8
+ def create_initializer_file
9
+ template 'initializer.rb', config_file_path
10
+ end
11
+
12
+ def create_services_dir
13
+ directory 'services', 'app/services'
14
+ end
15
+
16
+ private
17
+
18
+ def config_file_path
19
+ 'config/initializers/command_service_object.rb'
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ CommandServiceObject.configure do |config|
2
+ # By setting the append_controller_helper to false you will need to
3
+ # manually include the CommandServiceObject::ServiceControllerHelper
4
+ # module to your base controller.
5
+ # config.append_controller_helper = true
6
+ #
7
+ # The default command method name is :command
8
+ # but you can easily rename it to avoid collisions.
9
+ # config.command_method_name = :command
10
+ #
11
+ # Skip the generation of commands by the rails g service command
12
+ # config.skip_command = false
13
+ #
14
+ # Skip the generation of minitest/rspec by the rails g service command
15
+ # config.skip_test = false
16
+ #
17
+ # Skip the generation of errors by the rails g service command
18
+ # config.skip_error = true
19
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationService
4
+ class << self
5
+ def call(cmd)
6
+ raise Errors::InvalidCommand, cmd.class if cmd.invalid?
7
+
8
+ usecase = usecase_for(cmd).new(cmd)
9
+ usecase.call
10
+ rescue StandardError => e
11
+ if usecase
12
+ usecase.rollback_setters
13
+ usecase.rollback
14
+ end
15
+ handle_failure(e)
16
+ raise e
17
+ end
18
+
19
+ def handle_failure(failure)
20
+ # don't log custom failures if you want :D
21
+ return if failure.class.is_a?(CommandServiceObject::Failure)
22
+ #
23
+ # Add your logging logic
24
+ # ex:
25
+ # Rollbar.error(failure)
26
+ #
27
+ end
28
+
29
+ private
30
+
31
+ def usecase_for(cmd)
32
+ cmd.class.name.gsub('Commands', 'Usecases').constantize
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CaseBase
4
+ include CommandServiceObject::FailureHelper
5
+
6
+ attr_reader :payload
7
+
8
+ def initialize(payload)
9
+ @payload = payload
10
+ end
11
+
12
+ def rollback; end
13
+ end
@@ -1,114 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rubygems'
4
+ require_relative './setup/setup_generator.rb'
5
+ require_relative './usecase/usecase_generator.rb'
6
+ require_relative './command/command_generator.rb'
7
+ require_relative './test/test_generator.rb'
8
+ require 'rails/generators'
4
9
  require 'rails/generators/model_helpers'
5
10
 
6
- class ServiceGenerator < Rails::Generators::NamedBase
7
- include Rails::Generators::ModelHelpers
11
+ module Service
12
+ module Generators
13
+ class ServiceGenerator < Rails::Generators::NamedBase
14
+ argument :usecases, type: :array, default: [], banner: 'usecase usecase'
8
15
 
9
- source_root File.expand_path('templates', __dir__)
16
+ # Skiping options
17
+ class_option :skip_usecase, type: :boolean, default: false, aliases: '-U'
18
+ class_option :skip_command, type: :boolean, default: false, aliases: '-C'
19
+ class_option :skip_test, type: :boolean, default: false, aliases: '-T'
10
20
 
11
- argument :usecases, type: :array, default: [], banner: 'usecase usecase'
12
- class_option :skip_command, type: :boolean, default: false, aliases: '-C',
13
- desc: 'skip command file generation'
14
- class_option :skip_error, type: :boolean, default: false, aliases: '-E',
15
- desc: 'skip error file generation'
16
- class_option :skip_test, type: :boolean, default: false, aliases: '-T',
17
- desc: 'skip test file generation'
21
+ def install_if_not
22
+ return if File.exist?('app/services')
18
23
 
19
- def create_base_dir
20
- return if File.exist?('app/services')
24
+ generate 'service:install'
25
+ end
21
26
 
22
- directory 'base', 'app/services'
23
- end
27
+ def setup
28
+ invoke Service::Generators::SetupGenerator, [name]
29
+ end
24
30
 
25
- def add_controller_helper_to_application_controller
26
- application_controller_path = 'app/controllers/application_controller.rb'
31
+ def generate_usecases
32
+ return if options.skip_usecase?
27
33
 
28
- line = File.readlines(application_controller_path).select do |li|
29
- li =~ /class ApplicationController </
30
- end.first
34
+ invoke Service::Generators::UsecaseGenerator, [name, usecases]
35
+ end
31
36
 
32
- inject_into_file application_controller_path, after: line do
33
- " include ServiceControllerHelper\n"
34
- end
35
- end
37
+ def generate_commands
38
+ return if options.skip_command?
36
39
 
37
- def add_virtus_gem_to_gemfile
38
- gem 'virtus'
39
- end
40
+ invoke Service::Generators::CommandGenerator, [name, usecases]
41
+ end
40
42
 
41
- def create_service_dir
42
- return if File.exist?("app/services/#{service_name}")
43
+ def generate_tests
44
+ return if options.skip_test?
43
45
 
44
- empty_directory("app/services/#{service_name}")
45
- empty_directory("app/services/#{service_name}/usecases")
46
- empty_directory("app/services/#{service_name}/commands")
47
- empty_directory("app/services/#{service_name}/errors")
48
- end
49
-
50
- def generate_usecases
51
- usecases.each do |usecase|
52
- generate_usecase(usecase)
53
- generate_command(usecase)
54
- generate_error(usecase)
55
- generate_test(usecase)
46
+ invoke Service::Generators::TestGenerator, [name, usecases]
47
+ end
56
48
  end
57
49
  end
58
-
59
- private
60
-
61
- def generate_usecase(usecase)
62
- @usecase = usecase.classify
63
- path = "app/services/#{service_name}/usecases/#{usecase.underscore}.rb"
64
- template 'usecase.rb.erb', path
65
- end
66
-
67
- def generate_command(command)
68
- @command = command.classify
69
- path = "app/services/#{service_name}/commands/#{command.underscore}.rb"
70
- template 'command.rb.erb', path unless options.skip_command?
71
- end
72
-
73
- def generate_error(error)
74
- @error = error.classify
75
- path = "app/services/#{service_name}/errors/#{error.underscore}.rb"
76
- template 'error.rb.erb', path unless options.skip_error?
77
- end
78
-
79
- def generate_test(test)
80
- return if options.skip_test?
81
-
82
- if defined?(Minitest)
83
- empty_directory('test/services')
84
- generate_minitest_test_files(test)
85
- elsif defined?(RSpec)
86
- empty_directory('spec/services')
87
- generate_rspec_test_files(test)
88
- end
89
- end
90
-
91
- def generate_minitest_test_files(test)
92
- dir = "test/services/#{service_name}"
93
- empty_directory(dir)
94
-
95
- @test = test.classify
96
- path = "#{dir}/#{test.underscore}_test.rb"
97
-
98
- template 'minitest.rb.erb', path
99
- end
100
-
101
- def generate_rspec_test_files(test)
102
- dir = "spec/services/#{service_name}"
103
- empty_directory(dir)
104
-
105
- @test = test.classify
106
- path = "#{dir}/#{test.underscore}_spec.rb"
107
-
108
- template 'rspec.rb.erb', path
109
- end
110
-
111
- def service_name
112
- "#{name.underscore}_service"
113
- end
114
50
  end
@@ -0,0 +1,32 @@
1
+ require_relative '../setup/setup_generator.rb'
2
+
3
+ module Service
4
+ module Generators
5
+ class SetterGenerator < Rails::Generators::NamedBase
6
+ check_class_collision
7
+
8
+ source_root File.expand_path('templates', __dir__)
9
+
10
+ argument :setters, type: :array, default: [], banner: 'setters setters'
11
+
12
+ def setup
13
+ invoke Service::Generators::SetupGenerator, [name]
14
+ end
15
+
16
+ def create_setters
17
+ setters.each do |s|
18
+ @setter = s.classify
19
+
20
+ path = "app/services/#{service_name}/usecases/setters/#{s.underscore}.rb"
21
+ template 'setter.rb.erb', path
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def service_name
28
+ "#{name.underscore}_service"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= service_name.classify %>::Usecases::Setters
4
+ class <%= @setter %> < CaseBase
5
+ def call
6
+ # <payload>
7
+ end
8
+
9
+ def rollback
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ module Service
2
+ module Generators
3
+ class SetupGenerator < Rails::Generators::Base
4
+ def setup
5
+ return if File.exist?("app/services/#{service_name}")
6
+
7
+ empty_directory("app/services/#{service_name}")
8
+ empty_directory("app/services/#{service_name}/usecases")
9
+ empty_directory("app/services/#{service_name}/commands")
10
+ empty_directory("app/services/#{service_name}/usecases/setters")
11
+ empty_directory("app/services/#{service_name}/usecases/getters")
12
+ end
13
+
14
+ private
15
+
16
+ def service_name
17
+ "#{args.first.underscore}_service"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate service Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,56 @@
1
+ require_relative '../setup/setup_generator.rb'
2
+
3
+ module Service
4
+ module Generators
5
+ class TestGenerator < Rails::Generators::NamedBase
6
+ source_root File.expand_path('templates', __dir__)
7
+ argument :tests, type: :array, default: [], banner: 'usecase usecase'
8
+
9
+ def generate_test
10
+ return if options.skip_test?
11
+
12
+ if defined?(Minitest)
13
+ minitest_test
14
+ elsif defined?(RSpec)
15
+ rspec_test
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def minitest_test
22
+ dir = create_test_dir('test')
23
+
24
+ tests.each do |t|
25
+ @test = t.classify
26
+ path = "#{dir}/#{t.underscore}_test.rb"
27
+ template 'minitest.rb.erb', path
28
+ end
29
+ end
30
+
31
+ def rspec_test
32
+ dir = create_test_dir('spec')
33
+
34
+ tests.each do |t|
35
+ @test = t.classify
36
+ path = "#{dir}/#{t.underscore}_spec.rb"
37
+ template 'rspec.rb.erb', path
38
+ end
39
+ end
40
+
41
+ def create_test_dir(path)
42
+ test_path = "#{path}/services"
43
+ service_test = "#{test_path}/#{service_name}"
44
+
45
+ empty_directory(test_path) unless File.exist?(test_path)
46
+ empty_directory(service_test) unless File.exist?(service_test)
47
+
48
+ service_test
49
+ end
50
+
51
+ def service_name
52
+ "#{name.underscore}_service"
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate service Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module <%= service_name.classify %>::Usecases
4
- class <%= @usecase %> < ServiceBase
4
+ class <%= @usecase %> < CaseBase
5
+ include CommandServiceObject::Hooks
5
6
  #
6
7
  # Your business logic goes here, keep [call] method clean by using private
7
8
  # methods for Business logic.
@@ -10,12 +11,12 @@ module <%= service_name.classify %>::Usecases
10
11
  replace_me
11
12
  end
12
13
 
13
- private
14
+ # This method will run if call method raise error
15
+ def rollback
16
+ # rollback logic
17
+ end
14
18
 
15
- # This method will run if call method raise error
16
- def rollback
17
- # rollback logic
18
- end
19
+ private
19
20
 
20
21
  def replace_me
21
22
  # [business logic]
@@ -0,0 +1,29 @@
1
+ require_relative '../setup/setup_generator.rb'
2
+
3
+ module Service
4
+ module Generators
5
+ class UsecaseGenerator < Rails::Generators::NamedBase
6
+ check_class_collision
7
+
8
+ source_root File.expand_path('templates', __dir__)
9
+
10
+ argument :usecases, type: :array, default: [], banner: 'usecase usecase'
11
+
12
+ def call
13
+ invoke Service::Generators::SetupGenerator, [name]
14
+
15
+ usecases.each do |u|
16
+ @usecase = u.classify
17
+ path = "app/services/#{service_name}/usecases/#{u.underscore}.rb"
18
+ template 'usecase.rb.erb', path
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def service_name
25
+ "#{name.underscore}_service"
26
+ end
27
+ end
28
+ end
29
+ end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: command_service_object
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adham EL-Deeb
8
+ - Mohamed Diaa
8
9
  autorequire:
9
10
  bindir: exe
10
11
  cert_chain: []
11
- date: 2019-04-12 00:00:00.000000000 Z
12
+ date: 2019-04-30 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
@@ -24,6 +25,20 @@ dependencies:
24
25
  - - "~>"
25
26
  - !ruby/object:Gem::Version
26
27
  version: '2.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: byebug
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 9.0.6
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 9.0.6
27
42
  - !ruby/object:Gem::Dependency
28
43
  name: minitest
29
44
  requirement: !ruby/object:Gem::Requirement
@@ -104,6 +119,7 @@ description: command_service_object gem helps you to generate service and comman
104
119
  objects using rails generator.
105
120
  email:
106
121
  - adham.eldeeb90@gmail.com
122
+ - mohamed.diaa27@gmail.com
107
123
  executables: []
108
124
  extensions: []
109
125
  extra_rdoc_files: []
@@ -111,7 +127,9 @@ files:
111
127
  - ".gitignore"
112
128
  - ".rspec"
113
129
  - ".travis.yml"
130
+ - CHANGELOG.md
114
131
  - CODE_OF_CONDUCT.md
132
+ - CONTRIBUTING.md
115
133
  - Gemfile
116
134
  - Gemfile.lock
117
135
  - LICENSE.txt
@@ -121,23 +139,45 @@ files:
121
139
  - bin/setup
122
140
  - command_service_object.gemspec
123
141
  - lib/command_service_object.rb
142
+ - lib/command_service_object/configuration.rb
143
+ - lib/command_service_object/failure.rb
144
+ - lib/command_service_object/helpers/controller_helper.rb
145
+ - lib/command_service_object/helpers/failure_helper.rb
146
+ - lib/command_service_object/helpers/model_helper.rb
147
+ - lib/command_service_object/hooks.rb
148
+ - lib/command_service_object/railtie.rb
124
149
  - lib/command_service_object/version.rb
125
150
  - lib/generators/service/USAGE
151
+ - lib/generators/service/command/USAGE
152
+ - lib/generators/service/command/command_generator.rb
153
+ - lib/generators/service/command/templates/command.rb.erb
154
+ - lib/generators/service/getter/getter_generator.rb
155
+ - lib/generators/service/getter/templates/getter.rb.erb
156
+ - lib/generators/service/install/install_generator.rb
157
+ - lib/generators/service/install/templates/initializer.rb
158
+ - lib/generators/service/install/templates/services/application_service.rb
159
+ - lib/generators/service/install/templates/services/case_base.rb
160
+ - lib/generators/service/install/templates/services/service_result.rb
126
161
  - lib/generators/service/service_generator.rb
127
- - lib/generators/service/templates/base/application_service.rb
128
- - lib/generators/service/templates/base/service_base.rb
129
- - lib/generators/service/templates/base/service_controller_helper.rb
130
- - lib/generators/service/templates/base/service_result.rb
131
- - lib/generators/service/templates/command.rb.erb
132
- - lib/generators/service/templates/error.rb.erb
133
- - lib/generators/service/templates/minitest.rb.erb
134
- - lib/generators/service/templates/rspec.rb.erb
135
- - lib/generators/service/templates/usecase.rb.erb
162
+ - lib/generators/service/setter/setter_generator.rb
163
+ - lib/generators/service/setter/templates/setter.rb.erb
164
+ - lib/generators/service/setup/setup_generator.rb
165
+ - lib/generators/service/test/USAGE
166
+ - lib/generators/service/test/templates/minitest.rb.erb
167
+ - lib/generators/service/test/templates/rspec.rb.erb
168
+ - lib/generators/service/test/test_generator.rb
169
+ - lib/generators/service/usecase/USAGE
170
+ - lib/generators/service/usecase/templates/usecase.rb.erb
171
+ - lib/generators/service/usecase/usecase_generator.rb
136
172
  homepage: https://github.com/adham90/command_service_object
137
173
  licenses:
138
174
  - MIT
139
- metadata: {}
140
- post_install_message:
175
+ metadata:
176
+ homepage_uri: https://github.com/adham90/command_service_object
177
+ changelog_uri: https://github.com/adham90/command_service_object/blob/master/CHANGELOG.md
178
+ source_code_uri: https://github.com/adham90/command_service_object
179
+ bug_tracker_uri: https://github.com/adham90/command_service_object/issues
180
+ post_install_message: Yaaay!! CommandServiceObject is ready to rock your app!!
141
181
  rdoc_options: []
142
182
  require_paths:
143
183
  - lib
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class ApplicationService < ServiceBase
4
- def call
5
- ServiceResult.new do
6
- cmd.class.name.gsub('Commands', 'Usecases').constantize.call(cmd)
7
- end
8
- end
9
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class ServiceBase
4
- attr_reader :cmd
5
-
6
- def initialize(command)
7
- @cmd = command
8
- end
9
-
10
- def self.call(command)
11
- raise Errors::InvalidCommand, command.class if command.invalid?
12
-
13
- obj = new(command)
14
- obj.call
15
- rescue StandardError => e
16
- error(e)
17
- obj.send(:rollback)
18
- raise e
19
- end
20
-
21
- private
22
-
23
- def self.error(err)
24
- # don't log custom errors if you want :D
25
- return if err.class.name.start_with?(self.class.name.split('::').first)
26
-
27
- #
28
- # Add your logging logic
29
- # ex:
30
- # Rollbar.error(err)
31
- #
32
- end
33
-
34
- def rollback
35
- raise NotImplementedError
36
- end
37
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ServiceControllerHelper
4
- def self.included(base)
5
- base.extend ClassMethods
6
- end
7
-
8
- def command(service: nil, usecase: action_name)
9
- service_name = service || self.class.default_service || controller_name
10
-
11
- "#{service_name}/commands/#{usecase}".camelize.constantize
12
- end
13
-
14
- def execute(cmd)
15
- ApplicationService.call(cmd)
16
- end
17
-
18
- module ClassMethods
19
- @default_service = nil
20
-
21
- def default_service(service_name = nil)
22
- @default_service ||= service_name
23
- end
24
- end
25
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module <%= service_name.classify %>::Errors
4
- class <%= @error %> < StandardError
5
- def initialize(msg = "custom message")
6
- super(msg)
7
- end
8
- end
9
- end