auxiliary_rails 0.2.0 → 0.3.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 (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