command_service_object 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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