auxiliary_rails 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab-ci.yml +26 -0
  3. data/.rubocop.yml +11 -2
  4. data/.rubocop_todo.yml +13 -9
  5. data/.yardopts +5 -0
  6. data/CHANGELOG.md +19 -2
  7. data/CONTRIBUTING.md +0 -6
  8. data/Gemfile.lock +20 -16
  9. data/README.md +204 -3
  10. data/auxiliary_rails.gemspec +7 -5
  11. data/bin/rubocop +3 -0
  12. data/lib/auxiliary_rails.rb +5 -3
  13. data/lib/auxiliary_rails/application/command.rb +56 -0
  14. data/lib/auxiliary_rails/application/error.rb +10 -0
  15. data/lib/auxiliary_rails/application/form.rb +30 -0
  16. data/lib/auxiliary_rails/application/query.rb +78 -0
  17. data/lib/auxiliary_rails/cli.rb +19 -5
  18. data/lib/auxiliary_rails/concerns/performable.rb +141 -0
  19. data/lib/auxiliary_rails/version.rb +1 -1
  20. data/lib/generators/auxiliary_rails/install_commands_generator.rb +5 -0
  21. data/lib/generators/auxiliary_rails/install_generator.rb +0 -1
  22. data/lib/generators/auxiliary_rails/templates/application_error_template.rb +1 -1
  23. data/lib/generators/auxiliary_rails/templates/commands/application_command_template.rb +1 -1
  24. data/lib/generators/auxiliary_rails/templates/commands/command_template.rb +2 -2
  25. data/lib/generators/auxiliary_rails/templates/commands/commands.en_template.yml +5 -0
  26. data/templates/rails/elementary.rb +45 -9
  27. metadata +43 -11
  28. data/lib/auxiliary_rails/abstract_command.rb +0 -95
  29. data/lib/auxiliary_rails/abstract_error.rb +0 -7
  30. data/lib/generators/auxiliary_rails/install_rubocop_generator.rb +0 -29
  31. data/lib/generators/auxiliary_rails/templates/rubocop/rubocop_auxiliary_rails_template.yml +0 -65
  32. data/lib/generators/auxiliary_rails/templates/rubocop/rubocop_template.yml +0 -11
@@ -18,14 +18,14 @@ Gem::Specification.new do |spec|
18
18
  spec.license = 'MIT'
19
19
 
20
20
  if spec.respond_to?(:metadata)
21
- spec.metadata['homepage_uri'] = 'https://github.com/ergoserv/auxiliary_rails'
22
- spec.metadata['source_code_uri'] = 'https://github.com/ergoserv/auxiliary_rails'
23
- spec.metadata['changelog_uri'] = 'https://github.com/ergoserv/auxiliary_rails/blob/master/CHANGELOG.md'
21
+ spec.metadata['homepage_uri'] = spec.homepage
22
+ spec.metadata['source_code_uri'] = spec.homepage
23
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/releases"
24
24
  else
25
25
  raise 'RubyGems 2.0 or newer is required'
26
26
  end
27
27
 
28
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
28
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
29
29
  `git ls-files -z`.split("\x0").reject do |f|
30
30
  f.match(%r{^(test|spec|features)/})
31
31
  end
@@ -38,10 +38,12 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency 'rails', '>= 5.2', '< 7'
39
39
  spec.add_development_dependency 'rake'
40
40
  spec.add_development_dependency 'rspec', '~> 3.8'
41
- spec.add_development_dependency 'rubocop'
41
+ spec.add_development_dependency 'rubocop', '0.79'
42
42
  spec.add_development_dependency 'rubocop-performance'
43
43
  spec.add_development_dependency 'rubocop-rspec'
44
44
 
45
+ spec.add_runtime_dependency 'dry-core'
46
+ spec.add_runtime_dependency 'dry-initializer'
45
47
  spec.add_runtime_dependency 'dry-initializer-rails'
46
48
  spec.add_runtime_dependency 'thor'
47
49
  end
data/bin/rubocop ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ bundle exec rubocop "$@"
@@ -1,6 +1,8 @@
1
- require 'auxiliary_rails/abstract_error'
2
- require 'auxiliary_rails/abstract_command'
3
- require 'auxiliary_rails/railtie' if defined?(Rails)
1
+ require 'auxiliary_rails/application/command'
2
+ require 'auxiliary_rails/application/form'
3
+ require 'auxiliary_rails/application/error'
4
+ require 'auxiliary_rails/application/query'
5
+ require 'auxiliary_rails/railtie'
4
6
  require 'auxiliary_rails/version'
5
7
 
6
8
  module AuxiliaryRails
@@ -0,0 +1,56 @@
1
+ require 'active_model'
2
+ require 'auxiliary_rails/concerns/performable'
3
+ require 'dry-initializer-rails'
4
+
5
+ module AuxiliaryRails
6
+ module Application
7
+ # @abstract
8
+ class Command
9
+ extend Dry::Initializer
10
+ include AuxiliaryRails::Concerns::Performable
11
+
12
+ class << self
13
+ # @!method param(name, options = {})
14
+ # Defines param using <tt>Dry::Initializer</tt> format.
15
+ #
16
+ # @see Dry::Initializer
17
+ # @see https://dry-rb.org/gems/dry-initializer/3.0/params-and-options/
18
+ #
19
+ # @param name [Symbol]
20
+ # @param options [Hash]
21
+
22
+ # @!method option(name, options = {})
23
+ # Defines option using <tt>Dry::Initializer</tt> format.
24
+
25
+ # @see Dry::Initializer
26
+ # @see https://dry-rb.org/gems/dry-initializer/3.0/params-and-options/
27
+ #
28
+ # @param name [Symbol]
29
+ # @param options [Hash]
30
+
31
+ # Initializes command with <tt>args</tt> and runs <tt>#call</tt> method.
32
+ #
33
+ # @return [self]
34
+ def call(*args)
35
+ new(*args).call
36
+ end
37
+
38
+ # Defines `scope` for <tt>ActiveModel::Translation</tt>
39
+ #
40
+ # @return [Symbol]
41
+ def i18n_scope
42
+ :commands
43
+ end
44
+ end
45
+
46
+ protected
47
+
48
+ # Shortcut reader for attributes defined by <tt>Dry::Initializer</tt>
49
+ #
50
+ # @return [Hash]
51
+ def arguments
52
+ self.class.dry_initializer.attributes(self)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,10 @@
1
+ module AuxiliaryRails
2
+ module Application
3
+ class Error < StandardError
4
+ # @return [self] Creates new error object
5
+ def self.wrap(error)
6
+ new(error.message)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,30 @@
1
+ require 'active_model'
2
+
3
+ module AuxiliaryRails
4
+ module Application
5
+ # @abstract
6
+ class Form
7
+ include ActiveModel::Model
8
+ include ActiveModel::Attributes
9
+ include ActiveModel::AttributeAssignment
10
+ include AuxiliaryRails::Concerns::Performable
11
+
12
+ class << self
13
+ # Defines `scope` for <tt>ActiveModel::Translation</tt>
14
+ #
15
+ # @return [Symbol]
16
+ def i18n_scope
17
+ :forms
18
+ end
19
+ end
20
+
21
+ # Indicates object persistence.
22
+ #
23
+ # In case of form as performable object that means that form
24
+ # was executed with success.
25
+ def persisted?
26
+ performable_status == true
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,78 @@
1
+ require 'dry/core/class_attributes'
2
+ require 'dry-initializer'
3
+
4
+ module AuxiliaryRails
5
+ module Application
6
+ class Query
7
+ extend Dry::Core::ClassAttributes
8
+ extend Dry::Initializer
9
+
10
+ defines :default_relation
11
+
12
+ option :relation, default: proc { nil }
13
+
14
+ def self.call(*args)
15
+ new(*args).call
16
+ end
17
+
18
+ def call
19
+ ensure_proper_relation_types!
20
+
21
+ perform
22
+
23
+ query
24
+ end
25
+
26
+ def perform
27
+ raise NotImplementedError
28
+ end
29
+
30
+ def method_missing(method_name, *args, &block)
31
+ super unless query.respond_to?(method_name)
32
+
33
+ query.send(method_name, *args, &block)
34
+ end
35
+
36
+ def respond_to_missing?(method_name, include_private = false)
37
+ query.respond_to?(method_name) || super
38
+ end
39
+
40
+ private
41
+
42
+ # rubocop:disable Metrics/AbcSize, Style/GuardClause
43
+ def ensure_proper_relation_types!
44
+ if self.class.default_relation.nil?
45
+ error!('Undefined `default_relation`')
46
+ end
47
+ if !queriable_object?(self.class.default_relation)
48
+ error!('Invalid class of `default_relation`')
49
+ end
50
+ if !relation.nil? && !queriable_object?(relation)
51
+ error!('Invalid class of `relation` option')
52
+ end
53
+ end
54
+ # rubocop:enable Metrics/AbcSize, Style/GuardClause
55
+
56
+ def error!(message = nil)
57
+ raise error_class,
58
+ "`#{self.class}` #{message || 'Query raised an error.'}"
59
+ end
60
+
61
+ def error_class
62
+ AuxiliaryRails::Application::Error
63
+ end
64
+
65
+ def queriable_object?(object)
66
+ object.is_a?(ActiveRecord::Relation)
67
+ end
68
+
69
+ def query(scoped_query = nil)
70
+ @query ||= (relation || self.class.default_relation)
71
+
72
+ @query = scoped_query unless scoped_query.nil?
73
+
74
+ @query
75
+ end
76
+ end
77
+ end
78
+ end
@@ -6,6 +6,10 @@ module AuxiliaryRails
6
6
 
7
7
  TEMPLATES_DIR =
8
8
  File.expand_path("#{__dir__}/../../templates/")
9
+ REPOSITORY_URL =
10
+ 'https://raw.githubusercontent.com/ergoserv/' \
11
+ 'auxiliary_rails/develop/templates'
12
+ .freeze
9
13
 
10
14
  desc 'new APP_PATH', 'Create Rails application from template'
11
15
  long_desc <<-LONGDESC
@@ -17,20 +21,30 @@ module AuxiliaryRails
17
21
  option :database,
18
22
  default: 'postgresql',
19
23
  type: :string
20
- option :template_name,
24
+ option :template,
21
25
  default: 'elementary',
22
26
  type: :string
27
+ option :develop,
28
+ default: false,
29
+ type: :boolean
23
30
  def new(app_path)
24
31
  run "rails new #{app_path} " \
25
- '--skip-action-cable --skip-coffee --skip-test ' \
26
32
  "--database=#{options[:database]} " \
27
- "--template=#{rails_template_path(options[:template_name])}"
33
+ "--template=#{rails_template_path(options[:template])}" \
34
+ '--skip-action-cable ' \
35
+ '--skip-coffee ' \
36
+ '--skip-test ' \
37
+ '--skip-webpack-install'
28
38
  end
29
39
 
30
40
  private
31
41
 
32
- def rails_template_path(template_name)
33
- "#{TEMPLATES_DIR}/rails/#{template_name}.rb"
42
+ def rails_template_path(template)
43
+ if options[:develop] == true
44
+ "#{REPOSITORY_URL}/rails/#{template}.rb"
45
+ else
46
+ "#{TEMPLATES_DIR}/rails/#{template}.rb"
47
+ end
34
48
  end
35
49
  end
36
50
  end
@@ -0,0 +1,141 @@
1
+ require 'active_support/concern'
2
+
3
+ module AuxiliaryRails
4
+ module Concerns
5
+ module Performable
6
+ extend ActiveSupport::Concern
7
+ include ActiveModel::Validations
8
+
9
+ class_methods do
10
+ def call(*args)
11
+ new(*args).call
12
+ end
13
+ end
14
+
15
+ def call(options = {})
16
+ ensure_empty_status!
17
+
18
+ if options[:validate!] == true
19
+ validate!
20
+ elsif options[:validate] != false && invalid?
21
+ return failure!(:validation_failed)
22
+ end
23
+
24
+ perform
25
+
26
+ ensure_execution!
27
+ self
28
+ end
29
+
30
+ # Describes business logic.
31
+ #
32
+ # Method <b>should always</b> return <tt>success!</tt>
33
+ # or <tt>failure!</tt> methods in order pro provide further
34
+ # correct method chaining.
35
+ #
36
+ # @abstract
37
+ # @return [self]
38
+ def perform
39
+ raise NotImplementedError
40
+ end
41
+
42
+ def failure?
43
+ status?(:failure)
44
+ end
45
+
46
+ def status?(value)
47
+ ensure_execution!
48
+
49
+ performable_status == value&.to_sym
50
+ end
51
+
52
+ def success?
53
+ status?(:success)
54
+ end
55
+
56
+ # Provides ability to execude block of the code depending on
57
+ # command execution status
58
+ #
59
+ # @param status [Symol] Desired command status
60
+ # @param &_block Code to be executed if status matches
61
+ # @return [self]
62
+ def on(status, &_block)
63
+ ensure_execution!
64
+
65
+ return self unless status?(status)
66
+
67
+ yield(self) if block_given?
68
+
69
+ self
70
+ end
71
+
72
+ # Shortcut for <tt>ActiveRecord::Base.transaction</tt>
73
+ def transaction(&block)
74
+ ActiveRecord::Base.transaction(&block) if block_given?
75
+ end
76
+
77
+ protected
78
+
79
+ attr_accessor :performable_status
80
+
81
+ # @raise [AuxiliaryRails::Application::Error]
82
+ # Error happens if command contains any errors.
83
+ # @return [nil]
84
+ def ensure_empty_errors!
85
+ return if errors.empty?
86
+
87
+ error!("`#{self.class}` contains errors.")
88
+ end
89
+
90
+ def ensure_empty_status!
91
+ return if performable_status.nil?
92
+
93
+ error!("`#{self.class}` was already executed.")
94
+ end
95
+
96
+ def ensure_execution!
97
+ return if performable_status.present?
98
+
99
+ error!("`#{self.class}` was not executed yet.")
100
+ end
101
+
102
+ def error!(message = nil)
103
+ message ||= "`#{self.class}` raised error."
104
+ raise error_class, message
105
+ end
106
+
107
+ if defined?(ApplicationError)
108
+ def error_class
109
+ ApplicationError
110
+ end
111
+ else
112
+ def error_class
113
+ AuxiliaryRails::Application::Error
114
+ end
115
+ end
116
+
117
+ # Sets command's status to <tt>failure</tt>.
118
+ #
119
+ # @return [self]
120
+ def failure!(message = nil, options = {})
121
+ ensure_empty_status!
122
+
123
+ errors.add(:base, message, options) if message.present?
124
+
125
+ self.performable_status = :failure
126
+ self
127
+ end
128
+
129
+ # Sets command's status to <tt>success</tt>.
130
+ #
131
+ # @return [self]
132
+ def success!
133
+ ensure_empty_errors!
134
+ ensure_empty_status!
135
+
136
+ self.performable_status = :success
137
+ self
138
+ end
139
+ end
140
+ end
141
+ end
@@ -1,3 +1,3 @@
1
1
  module AuxiliaryRails
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '0.3.0'.freeze
3
3
  end
@@ -8,5 +8,10 @@ module AuxiliaryRails
8
8
  copy_file 'application_command_template.rb',
9
9
  'app/commands/application_command.rb'
10
10
  end
11
+
12
+ def copy_locale_command_file
13
+ copy_file 'commands.en_template.yml',
14
+ 'config/locales/commands.en.yml'
15
+ end
11
16
  end
12
17
  end
@@ -5,7 +5,6 @@ module AuxiliaryRails
5
5
  def install
6
6
  generate 'auxiliary_rails:install_commands'
7
7
  generate 'auxiliary_rails:install_errors'
8
- generate 'auxiliary_rails:install_rubocop --no-specify-gems'
9
8
  end
10
9
  end
11
10
  end