granite 0.9.4 → 0.9.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfd220e19b901b3778ae1a5934da2298a28a5435536401606e05faabdbaa80ae
4
- data.tar.gz: af299e280b01e76fca44edbb969b7e5d009424965367955c1ede05f24c10065b
3
+ metadata.gz: c916196599f14f9af76a9a550ffb51e7e4db5fd97deee1cf7cf04135c4bfb217
4
+ data.tar.gz: 6fc2f4a436734b34eb2096fa063a0d82e6fe6bf58afbb04af07b1a86d82d8727
5
5
  SHA512:
6
- metadata.gz: d7db61043e8e3039bea436f9d43807aaa2363c2ab537c1d613e326beb92f305c86e3ca8cae5eed59717bb8dd38edef29b7b37494873f7ec265f6e1d5b060a0e3
7
- data.tar.gz: a1360ff25d185e8c0848c1b385a5ba455025abfac7e691b1203e7b645bacd4aac5979436d096353ecbfb14aca6c7d66fef1c31374dbdf320ab7257e6e2193db8
6
+ metadata.gz: 0bd7b860deb8221df8be1e1227df3c71462862a47ba9243ec7ebc3be1972aeaa95b5c14334ab45aa372f7fe45fc89ed7b3af79a9fb52c3ed5f3e3908981611af
7
+ data.tar.gz: 6f164dc00ce5e56be2bff2bd01f22b49d37996decc05b74816a129f1598451d0dbbb184c1c7d02cac90e52eca80e947e8cba6932dba6842a030ce7801864ba0d
@@ -1,9 +1,9 @@
1
- require 'granite/projector/translations/helper'
2
1
  require 'action_controller'
3
2
 
4
3
  module Granite
5
4
  class Controller < Granite.base_controller_class
6
- include Granite::Projector::Translations::Helper
5
+ include Controller::Translations
6
+ helper Controller::Translations
7
7
 
8
8
  singleton_class.__send__(:attr_accessor, :projector_class)
9
9
  singleton_class.delegate :projector_path, :projector_name, :action_class, to: :projector_class
@@ -0,0 +1,15 @@
1
+ module Granite
2
+ class Controller
3
+ module Translations
4
+ def i18n_scopes
5
+ Granite::Translations.combine_paths(projector.i18n_scopes, [*action_name, nil])
6
+ end
7
+
8
+ def translate(*args, **options)
9
+ super(*Granite::Translations.scope_translation_args(i18n_scopes, *args, **options))
10
+ end
11
+
12
+ alias t translate
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ Lint/UselessAccessModifier:
2
+ ContextCreatingMethods:
3
+ - projector
data/lib/granite.rb CHANGED
@@ -4,6 +4,7 @@ require 'action_controller'
4
4
  require 'granite/version'
5
5
  require 'granite/config'
6
6
  require 'granite/context'
7
+ require 'granite/util'
7
8
 
8
9
  module Granite
9
10
  def self.config
@@ -7,10 +7,12 @@ require 'granite/action/types'
7
7
  require 'granite/action/error'
8
8
  require 'granite/action/performing'
9
9
  require 'granite/action/performer'
10
+ require 'granite/action/precondition'
10
11
  require 'granite/action/preconditions'
11
12
  require 'granite/action/policies'
12
13
  require 'granite/action/projectors'
13
14
  require 'granite/action/subject'
15
+ require 'granite/action/translations'
14
16
 
15
17
  module Granite
16
18
  class Action
@@ -38,6 +40,7 @@ module Granite
38
40
  end
39
41
 
40
42
  include Base
43
+ include Translations
41
44
  include Performing
42
45
  include Subject
43
46
  include Performer
@@ -64,10 +67,6 @@ module Granite
64
67
  end
65
68
  end
66
69
 
67
- def self.i18n_scope
68
- :granite_action
69
- end
70
-
71
70
  # Almost the same as Dirty `#changed?` method, but
72
71
  # doesn't check subject reference key
73
72
  def attributes_changed?(except: [])
@@ -0,0 +1,38 @@
1
+ module Granite
2
+ class Action
3
+ class Precondition < BasicObject
4
+ UNDEFINED = ::Object.new.freeze
5
+
6
+ def self.description(text = UNDEFINED)
7
+ case text
8
+ when UNDEFINED
9
+ @description
10
+ else
11
+ @description = text
12
+ end
13
+ end
14
+
15
+ def initialize(context)
16
+ @context = context
17
+ end
18
+
19
+ def call(*)
20
+ fail NotImplementedError, "#call method must be implemented for #{self.class}"
21
+ end
22
+
23
+ def method_missing(method_name, *args, &blk)
24
+ super unless @context.respond_to?(method_name)
25
+
26
+ @context.__send__(method_name, *args, &blk)
27
+ end
28
+
29
+ def respond_to_missing?(method_name, _include_private = false)
30
+ @context.respond_to?(method_name)
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :context
36
+ end
37
+ end
38
+ end
@@ -1,5 +1,6 @@
1
1
  require 'granite/action/preconditions/base_precondition'
2
2
  require 'granite/action/preconditions/embedded_precondition'
3
+ require 'granite/action/preconditions/object_precondition'
3
4
 
4
5
  module Granite
5
6
  class Action
@@ -13,6 +14,10 @@ module Granite
13
14
  extend ActiveSupport::Concern
14
15
 
15
16
  class PreconditionsCollection
17
+ include Enumerable
18
+
19
+ delegate :each, to: :@preconditions
20
+
16
21
  def initialize(*preconditions)
17
22
  @preconditions = preconditions.flatten
18
23
  end
@@ -43,8 +48,10 @@ module Granite
43
48
  options = args.extract_options!
44
49
  if block
45
50
  add_precondition(BasePrecondition, options, &block)
51
+ elsif args.first.is_a?(Class)
52
+ add_precondition(ObjectPrecondition, *args, options)
46
53
  else
47
- common_options = options.extract!(:if, :unless)
54
+ common_options = options.extract!(:if, :unless, :desc, :description)
48
55
  args.each do |type|
49
56
  precondition common_options.merge(type => {})
50
57
  end
@@ -9,10 +9,7 @@ module Granite
9
9
  end
10
10
 
11
11
  def execute!(context)
12
- return if @options[:if] && !context.instance_exec(&@options[:if])
13
- return if @options[:unless] && context.instance_exec(&@options[:unless])
14
-
15
- _execute(context)
12
+ _execute(context) if context.conditions_satisfied?(@options)
16
13
  end
17
14
 
18
15
  private
@@ -0,0 +1,15 @@
1
+ require 'granite/action/preconditions/base_precondition'
2
+
3
+ module Granite
4
+ class Action
5
+ module Preconditions
6
+ class ObjectPrecondition < BasePrecondition
7
+ private
8
+
9
+ def _execute(context)
10
+ @args.first.new(context).call(**@options.except(:if, :unless))
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ module Granite
2
+ class Action
3
+ module Translations
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def i18n_scope
8
+ :granite_action
9
+ end
10
+
11
+ def i18n_scopes
12
+ lookup_ancestors.flat_map do |klass|
13
+ :"#{klass.i18n_scope}.#{klass.model_name.i18n_key}"
14
+ end + [nil]
15
+ end
16
+ end
17
+
18
+ def translate(*args, **options)
19
+ I18n.translate(*Granite::Translations.scope_translation_args(self.class.i18n_scopes, *args, **options))
20
+ end
21
+ alias t translate
22
+ end
23
+ end
24
+ end
data/lib/granite/base.rb CHANGED
@@ -18,7 +18,7 @@ module Granite
18
18
  include ActiveData::Model::Primary
19
19
  include ActiveModel::Validations::Callbacks
20
20
 
21
- include Granite::Translations
21
+ include Granite::Util
22
22
  include Granite::Represents
23
23
  end
24
24
  end
@@ -1,52 +1,17 @@
1
1
  module Granite
2
2
  class Projector
3
3
  module Translations
4
- extend ActiveSupport::Concern
4
+ include ActionView::Helpers::TranslationHelper
5
5
 
6
- class TranslationsWrapper
7
- include ActionView::Helpers::TranslationHelper
6
+ def i18n_scopes
7
+ Granite::Translations.combine_paths(action_class.i18n_scopes, [:"#{projector_name}"])
8
8
  end
9
9
 
10
- def translate(*args)
11
- TranslationsWrapper.new.translate(*self.class.scope_translation_args_by_projector(args))
10
+ def translate(*args, **options)
11
+ super(*Granite::Translations.scope_translation_args(i18n_scopes, *args, **options))
12
12
  end
13
- alias t translate
14
-
15
- module ClassMethods
16
- def scope_translation_args_by_projector(args, action_name: nil)
17
- options = args.extract_options!
18
-
19
- lookups = expand_relative_key(args.first, action_name).map(&:to_sym)
20
- lookups += [options[:default]]
21
- lookups = lookups.flatten.compact
22
-
23
- key = lookups.shift
24
- options[:default] = lookups
25
-
26
- [key, options]
27
- end
28
-
29
- private
30
13
 
31
- def expand_relative_key(key, action_name = nil)
32
- return [key] unless key.is_a?(String) && key.start_with?('.')
33
-
34
- base_keys = extract_base_keys(key, action_name)
35
-
36
- action_class.lookup_ancestors.map do |klass|
37
- base_keys.map do |base_key|
38
- :"#{klass.i18n_scope}.#{klass.model_name.i18n_key}.#{base_key}"
39
- end
40
- end.flatten + base_keys
41
- end
42
-
43
- def extract_base_keys(key, action_name)
44
- undotted_key = key.sub(/^\./, '')
45
- base_keys = [:"#{projector_name}.#{undotted_key}"]
46
- base_keys.unshift :"#{projector_name}.#{action_name}.#{undotted_key}" if action_name
47
- base_keys
48
- end
49
- end
14
+ alias t translate
50
15
  end
51
16
  end
52
17
  end
@@ -11,9 +11,7 @@ module Granite
11
11
  end
12
12
 
13
13
  def sync
14
- return if reference.nil?
15
-
16
- reference.public_send(writer, read)
14
+ reference.public_send(writer, read) if reference.respond_to?(writer)
17
15
  end
18
16
 
19
17
  def typecast(value)
@@ -5,8 +5,8 @@ module Granite
5
5
  module Routing
6
6
  module Mapper
7
7
  def granite(projector_path, **options)
8
- route = Route.new(projector_path, options.extract!(:path, :as, :projector_prefix))
9
- Declarer.declare(self, route, options)
8
+ route = Route.new(projector_path, **options.extract!(:path, :as, :projector_prefix))
9
+ Declarer.declare(self, route, **options)
10
10
  end
11
11
  end
12
12
  end
@@ -1,19 +1,14 @@
1
1
  module Granite
2
- module Translations
3
- extend ActiveSupport::Concern
4
-
5
- def translate(*args)
6
- I18n.translate(*self.class.scope_translation_args(args))
7
- end
8
- alias t translate
9
-
10
- module ClassMethods
11
- def scope_translation_args(args)
12
- options = args.extract_options!
2
+ class Translations
3
+ class << self
4
+ def combine_paths(paths1, paths2)
5
+ paths1.flat_map do |path1|
6
+ paths2.map { |path2| [*path1, *path2].join('.') }
7
+ end
8
+ end
13
9
 
14
- lookups = expand_relative_key(args.first).map(&:to_sym)
15
- lookups += [options[:default]]
16
- lookups = lookups.flatten.compact
10
+ def scope_translation_args(scopes, key, *, **options)
11
+ lookups = expand_relative_key(scopes, key) + Array(options[:default])
17
12
 
18
13
  key = lookups.shift
19
14
  options[:default] = lookups
@@ -23,14 +18,10 @@ module Granite
23
18
 
24
19
  private
25
20
 
26
- def expand_relative_key(key)
21
+ def expand_relative_key(scopes, key)
27
22
  return [key] unless key.is_a?(String) && key.start_with?('.')
28
23
 
29
- base_key = key.sub(/^\./, '')
30
-
31
- lookup_ancestors.map do |klass|
32
- :"#{klass.i18n_scope}.#{klass.model_name.i18n_key}.#{base_key}"
33
- end.flatten + [base_key]
24
+ combine_paths(scopes, [key.sub(/^\./, '')]).map(&:to_sym)
34
25
  end
35
26
  end
36
27
  end
@@ -0,0 +1,51 @@
1
+ module Granite
2
+ module Util
3
+ extend ActiveSupport::Concern
4
+
5
+ # Evaluates value and returns result based on what was passed:
6
+ # - if Proc was passed, then executes it in context of self
7
+ # - if Symbol was passed, then calls a method with that name and returns result
8
+ # - otherwise just returns the value itself
9
+ # @param value [Object] value to evaluate
10
+ # @return [Object] result of evaluation
11
+ def evaluate(value)
12
+ case value
13
+ when Proc
14
+ evaluate_proc(value)
15
+ when Symbol
16
+ evaluate_symbol(value)
17
+ else
18
+ value
19
+ end
20
+ end
21
+
22
+ # Evaluates `if` or `unless` conditions present in the supplied
23
+ # `options` being it a symbol or callable.
24
+ #
25
+ # @param [Hash] options The method options to evaluate.
26
+ # @option options :if method name or callable
27
+ # @option options :unless method name or callable
28
+ # @return [Boolean] whether conditions are satisfied
29
+ def conditions_satisfied?(options)
30
+ fail ArgumentError, 'You cannot specify both if and unless' if options.key?(:if) && options.key?(:unless)
31
+
32
+ if options.key?(:if)
33
+ evaluate(options[:if])
34
+ elsif options.key?(:unless)
35
+ !evaluate(options[:unless])
36
+ else
37
+ true
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def evaluate_proc(value)
44
+ instance_exec(&value)
45
+ end
46
+
47
+ def evaluate_symbol(value)
48
+ __send__(value)
49
+ end
50
+ end
51
+ end
@@ -1,3 +1,3 @@
1
1
  module Granite
2
- VERSION = '0.9.4'.freeze
2
+ VERSION = '0.9.9'.freeze
3
3
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ require_relative 'rubocop/granite'
6
+ require_relative 'rubocop/granite/inject'
7
+
8
+ RuboCop::Granite::Inject.defaults!
@@ -0,0 +1,9 @@
1
+ module RuboCop
2
+ module Granite
3
+ PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
4
+ CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'rubocop-default.yml').freeze
5
+ CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
6
+
7
+ private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The original code is from https://github.com/rubocop-hq/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb
4
+ # See https://github.com/rubocop-hq/rubocop-rspec/blob/master/MIT-LICENSE.md
5
+ module RuboCop
6
+ module Granite
7
+ # Because RuboCop doesn't yet support plugins, we have to monkey patch in a
8
+ # bit of our configuration.
9
+ module Inject
10
+ def self.defaults!
11
+ path = CONFIG_DEFAULT.to_s
12
+ hash = ConfigLoader.load_file(path)
13
+ config = Config.new(hash, path).tap(&:make_excludes_absolute)
14
+ puts "configuration from #{path}" if ConfigLoader.debug?
15
+ config = ConfigLoader.merge_with_default(config, path)
16
+ ConfigLoader.instance_variable_set(:@default_configuration, config)
17
+ end
18
+ end
19
+ end
20
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: granite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.4
4
+ version: 0.9.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arkadiy Zabazhanov & friends
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-31 00:00:00.000000000 Z
11
+ date: 2021-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -244,28 +244,42 @@ dependencies:
244
244
  requirements:
245
245
  - - "~>"
246
246
  - !ruby/object:Gem::Version
247
- version: '0.52'
247
+ version: 0.78.0
248
248
  type: :development
249
249
  prerelease: false
250
250
  version_requirements: !ruby/object:Gem::Requirement
251
251
  requirements:
252
252
  - - "~>"
253
253
  - !ruby/object:Gem::Version
254
- version: '0.52'
254
+ version: 0.78.0
255
+ - !ruby/object:Gem::Dependency
256
+ name: rubocop-rails
257
+ requirement: !ruby/object:Gem::Requirement
258
+ requirements:
259
+ - - "~>"
260
+ - !ruby/object:Gem::Version
261
+ version: 2.4.1
262
+ type: :development
263
+ prerelease: false
264
+ version_requirements: !ruby/object:Gem::Requirement
265
+ requirements:
266
+ - - "~>"
267
+ - !ruby/object:Gem::Version
268
+ version: 2.4.1
255
269
  - !ruby/object:Gem::Dependency
256
270
  name: rubocop-rspec
257
271
  requirement: !ruby/object:Gem::Requirement
258
272
  requirements:
259
273
  - - "~>"
260
274
  - !ruby/object:Gem::Version
261
- version: '1.22'
275
+ version: 1.37.0
262
276
  type: :development
263
277
  prerelease: false
264
278
  version_requirements: !ruby/object:Gem::Requirement
265
279
  requirements:
266
280
  - - "~>"
267
281
  - !ruby/object:Gem::Version
268
- version: '1.22'
282
+ version: 1.37.0
269
283
  - !ruby/object:Gem::Dependency
270
284
  name: simplecov
271
285
  requirement: !ruby/object:Gem::Requirement
@@ -288,6 +302,8 @@ extra_rdoc_files: []
288
302
  files:
289
303
  - LICENSE
290
304
  - app/controllers/granite/controller.rb
305
+ - app/controllers/granite/controller/translations.rb
306
+ - config/rubocop-default.yml
291
307
  - lib/generators/USAGE
292
308
  - lib/generators/granite/install_controller_generator.rb
293
309
  - lib/generators/granite_generator.rb
@@ -305,14 +321,17 @@ files:
305
321
  - lib/granite/action/policies/always_allow_strategy.rb
306
322
  - lib/granite/action/policies/any_strategy.rb
307
323
  - lib/granite/action/policies/required_performer_strategy.rb
324
+ - lib/granite/action/precondition.rb
308
325
  - lib/granite/action/preconditions.rb
309
326
  - lib/granite/action/preconditions/base_precondition.rb
310
327
  - lib/granite/action/preconditions/embedded_precondition.rb
328
+ - lib/granite/action/preconditions/object_precondition.rb
311
329
  - lib/granite/action/projectors.rb
312
330
  - lib/granite/action/subject.rb
313
331
  - lib/granite/action/transaction.rb
314
332
  - lib/granite/action/transaction_manager.rb
315
333
  - lib/granite/action/transaction_manager/transactions_stack.rb
334
+ - lib/granite/action/translations.rb
316
335
  - lib/granite/action/types.rb
317
336
  - lib/granite/action/types/collection.rb
318
337
  - lib/granite/base.rb
@@ -327,8 +346,6 @@ files:
327
346
  - lib/granite/projector/error.rb
328
347
  - lib/granite/projector/helpers.rb
329
348
  - lib/granite/projector/translations.rb
330
- - lib/granite/projector/translations/helper.rb
331
- - lib/granite/projector/translations/view_helper.rb
332
349
  - lib/granite/rails.rb
333
350
  - lib/granite/represents.rb
334
351
  - lib/granite/represents/attribute.rb
@@ -348,7 +365,11 @@ files:
348
365
  - lib/granite/rspec/satisfy_preconditions.rb
349
366
  - lib/granite/translations.rb
350
367
  - lib/granite/typecasters.rb
368
+ - lib/granite/util.rb
351
369
  - lib/granite/version.rb
370
+ - lib/rubocop-granite.rb
371
+ - lib/rubocop/granite.rb
372
+ - lib/rubocop/granite/inject.rb
352
373
  homepage: https://github.com/toptal/granite
353
374
  licenses:
354
375
  - MIT
@@ -368,7 +389,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
368
389
  - !ruby/object:Gem::Version
369
390
  version: '0'
370
391
  requirements: []
371
- rubygems_version: 3.0.6
392
+ rubygems_version: 3.0.9
372
393
  signing_key:
373
394
  specification_version: 4
374
395
  summary: Another business actions architecture for Rails apps
@@ -1,22 +0,0 @@
1
- require 'granite/projector/translations/view_helper'
2
-
3
- module Granite
4
- class Projector
5
- module Translations
6
- module Helper
7
- extend ActiveSupport::Concern
8
-
9
- included do
10
- delegate :scope_translation_args_by_projector, to: :projector_class
11
- helper_method :scope_translation_args_by_projector
12
- helper ViewHelper
13
- end
14
-
15
- def translate(*args)
16
- super(*scope_translation_args_by_projector(args, action_name: action_name))
17
- end
18
- alias t translate
19
- end
20
- end
21
- end
22
- end
@@ -1,12 +0,0 @@
1
- module Granite
2
- class Projector
3
- module Translations
4
- module ViewHelper
5
- def translate(*args)
6
- super(*scope_translation_args_by_projector(args, action_name: action_name))
7
- end
8
- alias t translate
9
- end
10
- end
11
- end
12
- end