granite 0.7.0 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 171acd12e388c4b1016581a76445ff1ae6dc9051
4
- data.tar.gz: be9fdc3c8d64c3caab3c4ee0f944cbe3892d965d
3
+ metadata.gz: eee58f357db73ca54fa35ec5a68a13081bd450a8
4
+ data.tar.gz: 1042435a47b006d54caafc174552863a2024a52d
5
5
  SHA512:
6
- metadata.gz: 4773a166e6b738430fa0300894bb4889c603404a2cba4dfc2a703000de1f7cb1679742abaf9e9ec2872f4edf1b397524abc3b0bc89b7c4ca99a57e44c5c33bbd
7
- data.tar.gz: 61a75b1ecd04c0a43c13e8b06714080fdc31bdeeda6f6b0d52fabb19d9723fbfd73bf10a5747f4306962c96c8a214910e5796c74d9fe2dc63d84cdee463c69f9
6
+ metadata.gz: 59143c029f08dae76509be73e06b653eedbfb29b98cf8b79ffebcd0eb0183fd63fe9312a0fa51c8d7806097e5a70d7168e87e116c45ce7e16af3211886b03ed4
7
+ data.tar.gz: f3d6579fbd80170a55a3fef47e90db59236087a0ecd4b14c1f54f145553b38bc118efd7f24a535b5d6225143511db18b26f82187bcebb3f384063c03bdc997f2
@@ -3,7 +3,7 @@ require 'rails/generators/base'
3
3
  module Granite
4
4
  module Generators
5
5
  class InstallControllerGenerator < Rails::Generators::Base
6
- source_root File.expand_path('../../../..', __FILE__)
6
+ source_root File.expand_path('../../..', __dir__)
7
7
 
8
8
  desc 'Creates a Granite::Controller for further customization'
9
9
 
@@ -1,5 +1,5 @@
1
1
  class GraniteGenerator < Rails::Generators::NamedBase
2
- source_root File.expand_path('../templates', __FILE__)
2
+ source_root File.expand_path('templates', __dir__)
3
3
 
4
4
  argument :projector, type: :string, required: false
5
5
  class_option :collection, type: :boolean, aliases: '-C', desc: 'Generate collection action'
@@ -1,6 +1,7 @@
1
1
  require 'active_support/dependencies'
2
2
  require 'action_controller'
3
3
 
4
+ require 'granite/version'
4
5
  require 'granite/config'
5
6
  require 'granite/context'
6
7
 
@@ -17,8 +18,11 @@ module Granite
17
18
  singleton_class.delegate(*Granite::Context.delegated, to: :context)
18
19
  end
19
20
 
21
+ require 'granite/base'
20
22
  require 'granite/dispatcher'
21
23
  require 'granite/action'
22
24
  require 'granite/projector'
23
25
  require 'granite/routing'
24
26
  require 'granite/rails' if defined?(::Rails)
27
+
28
+ ActiveData.base_concern = Granite::Base
@@ -4,14 +4,12 @@ require 'active_record/validations'
4
4
  require 'active_support/callbacks'
5
5
 
6
6
  require 'granite/action/types'
7
- require 'granite/action/represents'
8
7
  require 'granite/action/error'
9
8
  require 'granite/action/performing'
10
9
  require 'granite/action/performer'
11
10
  require 'granite/action/preconditions'
12
11
  require 'granite/action/policies'
13
12
  require 'granite/action/projectors'
14
- require 'granite/action/translations'
15
13
  require 'granite/action/subject'
16
14
 
17
15
  module Granite
@@ -41,20 +39,13 @@ module Granite
41
39
  end
42
40
  end
43
41
 
44
- include ActiveSupport::Callbacks
45
- include ActiveData::Model
46
- include ActiveData::Model::Representation
47
- include ActiveData::Model::Associations
48
- include ActiveData::Model::Dirty
49
- include ActiveModel::Validations::Callbacks
42
+ include Base
50
43
  include Performing
51
44
  include Subject
52
45
  include Performer
53
46
  include Preconditions
54
47
  include Policies
55
48
  include Projectors
56
- include Translations
57
- include Represents
58
49
  prepend AssignAttributes
59
50
 
60
51
  handle_exception ActiveRecord::RecordInvalid do |e|
@@ -89,7 +89,8 @@ module Granite
89
89
  def try_perform!(context: nil, **options)
90
90
  return unless satisfy_preconditions?
91
91
  transactional do
92
- perform!(context: context, **options)
92
+ validate!(context)
93
+ perform_action!(**options)
93
94
  end
94
95
  end
95
96
 
@@ -0,0 +1,24 @@
1
+ require 'active_data/model'
2
+ require 'active_data/model/primary'
3
+ require 'active_data/model/lifecycle'
4
+ require 'active_data/model/associations'
5
+
6
+ require 'granite/translations'
7
+ require 'granite/represents'
8
+
9
+ module Granite
10
+ module Base
11
+ extend ActiveSupport::Concern
12
+
13
+ include ActiveSupport::Callbacks
14
+ include ActiveData::Model
15
+ include ActiveData::Model::Representation
16
+ include ActiveData::Model::Dirty
17
+ include ActiveData::Model::Associations
18
+ include ActiveData::Model::Primary
19
+ include ActiveModel::Validations::Callbacks
20
+
21
+ include Granite::Translations
22
+ include Granite::Represents
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'granite/represents/reflection'
2
+
3
+ module Granite
4
+ module Represents
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ private
9
+
10
+ def represents(*fields, &block)
11
+ options = fields.extract_options!.symbolize_keys
12
+
13
+ fields.each do |field|
14
+ add_attribute Granite::Represents::Reflection, field, options, &block
15
+
16
+ before_validation do
17
+ attribute(field).sync if __send__ "#{field}_changed?"
18
+ true
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,89 @@
1
+ module Granite
2
+ module Represents
3
+ class Attribute < ActiveData::Model::Attributes::Attribute
4
+ delegate :writer, :reader, :reader_before_type_cast, to: :reflection
5
+
6
+ def initialize(*_args)
7
+ super
8
+
9
+ set_default_value
10
+ set_default_value_before_type_cast
11
+ end
12
+
13
+ def sync
14
+ return if reference.nil?
15
+ reference.public_send(writer, read)
16
+ end
17
+
18
+ def typecast(value)
19
+ return value if value.class == type
20
+
21
+ typecaster.call(value, self) unless value.nil?
22
+ end
23
+
24
+ def type
25
+ return reflection.options[:type] if reflection.options[:type].present?
26
+ active_data_type || type_from_type_for_attribute || super
27
+ end
28
+
29
+ def typecaster
30
+ @typecaster ||= begin
31
+ type_class = type.instance_of?(Class) ? type : type.class
32
+ @typecaster = ActiveData.typecaster(type_class.ancestors.grep(Class))
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def reference
39
+ owner.__send__(reflection.reference)
40
+ end
41
+
42
+ def set_default_value
43
+ return unless reference.respond_to?(reader)
44
+
45
+ variable_cache(:value) do
46
+ normalize(enumerize(reference.public_send(reader)))
47
+ end
48
+ end
49
+
50
+ def set_default_value_before_type_cast
51
+ return unless reference.respond_to?(reader_before_type_cast)
52
+
53
+ variable_cache(:value_before_type_cast) do
54
+ defaultize(reference.public_send(reader_before_type_cast))
55
+ end
56
+ end
57
+
58
+ def active_data_type
59
+ return nil unless reference.is_a?(ActiveData::Model)
60
+
61
+ reference_attribute = reference.attribute(name)
62
+
63
+ return Granite::Action::Types::Collection.new(reference_attribute.type) if [
64
+ ActiveData::Model::Attributes::ReferenceMany,
65
+ ActiveData::Model::Attributes::Collection,
66
+ ActiveData::Model::Attributes::Dictionary
67
+ ].any? { |klass| reference_attribute.is_a? klass }
68
+
69
+ reference_attribute.type # TODO: create `type_for_attribute` method inside of ActiveData
70
+ end
71
+
72
+ def type_from_type_for_attribute
73
+ return nil unless reference.respond_to?(:type_for_attribute)
74
+
75
+ attribute_type = reference.type_for_attribute(name.to_s)
76
+
77
+ return Granite::Action::Types::Collection.new(convert_type_to_value_class(attribute_type.subtype)) if attribute_type.respond_to?(:subtype)
78
+
79
+ convert_type_to_value_class(attribute_type)
80
+ end
81
+
82
+ def convert_type_to_value_class(attribute_type)
83
+ return attribute_type.value_class if attribute_type.respond_to?(:value_class)
84
+
85
+ ActiveData::Model::Associations::PersistenceAdapters::ActiveRecord::TYPES[attribute_type.type&.to_sym]
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,24 @@
1
+ require 'granite/represents/attribute'
2
+
3
+ module Granite
4
+ module Represents
5
+ class Reflection < ActiveData::Model::Attributes::Reflections::Represents
6
+ class << self
7
+ def build(target, generated_methods, name, *args, &block)
8
+ options = args.last
9
+
10
+ reference = target.reflect_on_association(options[:of]) if target.respond_to?(:reflect_on_association)
11
+ reference ||= target.reflect_on_attribute(options[:of]) if target.respond_to?(:reflect_on_attribute)
12
+
13
+ target.validates_presence_of(reference.name) if reference
14
+
15
+ super(target, generated_methods, name, *args, &block)
16
+ end
17
+
18
+ def attribute_class
19
+ @attribute_class ||= Granite::Represents::Attribute
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,37 @@
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!
13
+
14
+ lookups = expand_relative_key(args.first).map(&:to_sym)
15
+ lookups += [options[:default]]
16
+ lookups = lookups.flatten.compact
17
+
18
+ key = lookups.shift
19
+ options[:default] = lookups
20
+
21
+ [key, options]
22
+ end
23
+
24
+ private
25
+
26
+ def expand_relative_key(key)
27
+ return [key] unless key.is_a?(String) && key.start_with?('.')
28
+
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]
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module Granite
2
+ VERSION = '0.8.0'.freeze
3
+ 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.7.0
4
+ version: 0.8.0
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: 2018-02-23 00:00:00.000000000 Z
11
+ date: 2018-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: active_data
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 1.1.0
33
+ version: 1.1.2
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 1.1.0
40
+ version: 1.1.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: activesupport
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "<"
123
123
  - !ruby/object:Gem::Version
124
124
  version: '1'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry-byebug
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: rspec
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -276,14 +290,11 @@ files:
276
290
  - lib/granite/action/preconditions/base_precondition.rb
277
291
  - lib/granite/action/preconditions/embedded_precondition.rb
278
292
  - lib/granite/action/projectors.rb
279
- - lib/granite/action/represents.rb
280
- - lib/granite/action/represents/attribute.rb
281
- - lib/granite/action/represents/reflection.rb
282
293
  - lib/granite/action/subject.rb
283
294
  - lib/granite/action/transaction.rb
284
- - lib/granite/action/translations.rb
285
295
  - lib/granite/action/types.rb
286
296
  - lib/granite/action/types/collection.rb
297
+ - lib/granite/base.rb
287
298
  - lib/granite/config.rb
288
299
  - lib/granite/context.rb
289
300
  - lib/granite/dispatcher.rb
@@ -298,6 +309,9 @@ files:
298
309
  - lib/granite/projector/translations/helper.rb
299
310
  - lib/granite/projector/translations/view_helper.rb
300
311
  - lib/granite/rails.rb
312
+ - lib/granite/represents.rb
313
+ - lib/granite/represents/attribute.rb
314
+ - lib/granite/represents/reflection.rb
301
315
  - lib/granite/routing.rb
302
316
  - lib/granite/routing/cache.rb
303
317
  - lib/granite/routing/caching.rb
@@ -311,6 +325,8 @@ files:
311
325
  - lib/granite/rspec/projector_helpers.rb
312
326
  - lib/granite/rspec/raise_validation_error.rb
313
327
  - lib/granite/rspec/satisfy_preconditions.rb
328
+ - lib/granite/translations.rb
329
+ - lib/granite/version.rb
314
330
  homepage: https://github.com/toptal/granite
315
331
  licenses:
316
332
  - MIT
@@ -1,26 +0,0 @@
1
- require 'granite/action/represents/reflection'
2
-
3
- module Granite
4
- class Action
5
- module Represents
6
- extend ActiveSupport::Concern
7
-
8
- module ClassMethods
9
- private
10
-
11
- def represents(*fields, &block)
12
- options = fields.extract_options!.symbolize_keys
13
-
14
- fields.each do |field|
15
- add_attribute Granite::Action::Represents::Reflection, field, options, &block
16
-
17
- before_validation do
18
- attribute(field).sync if __send__ "#{field}_changed?"
19
- true
20
- end
21
- end
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,90 +0,0 @@
1
- module Granite
2
- class Action
3
- module Represents
4
- class Attribute < ActiveData::Model::Attributes::Attribute
5
- delegate :writer, :reader, :reader_before_type_cast, to: :reflection
6
-
7
- def initialize(*_args)
8
- super
9
-
10
- set_default_value
11
- set_default_value_before_type_cast
12
- end
13
-
14
- def sync
15
- reference.public_send(writer, read)
16
- end
17
-
18
- def typecast(value)
19
- return value if value.class == type
20
-
21
- typecaster.call(value, self) unless value.nil?
22
- end
23
-
24
- def type
25
- return reflection.options[:type] if reflection.options[:type].present?
26
- active_data_type || type_from_type_for_attribute || super
27
- end
28
-
29
- def typecaster
30
- @typecaster ||= begin
31
- type_class = type.instance_of?(Class) ? type : type.class
32
- @typecaster = ActiveData.typecaster(type_class.ancestors.grep(Class))
33
- end
34
- end
35
-
36
- private
37
-
38
- def reference
39
- owner.__send__(reflection.reference)
40
- end
41
-
42
- def set_default_value
43
- return unless reference.respond_to?(reader)
44
-
45
- variable_cache(:value) do
46
- normalize(enumerize(reference.public_send(reader)))
47
- end
48
- end
49
-
50
- def set_default_value_before_type_cast
51
- return unless reference.respond_to?(reader_before_type_cast)
52
-
53
- variable_cache(:value_before_type_cast) do
54
- defaultize(reference.public_send(reader_before_type_cast))
55
- end
56
- end
57
-
58
- def active_data_type
59
- return nil unless reference.is_a?(ActiveData::Model)
60
-
61
- reference_attribute = reference.attribute(name)
62
-
63
- return Granite::Action::Types::Collection.new(reference_attribute.type) if [
64
- ActiveData::Model::Attributes::ReferenceMany,
65
- ActiveData::Model::Attributes::Collection,
66
- ActiveData::Model::Attributes::Dictionary
67
- ].any? { |klass| reference_attribute.is_a? klass }
68
-
69
- reference_attribute.type # TODO: create `type_for_attribute` method inside of ActiveData
70
- end
71
-
72
- def type_from_type_for_attribute
73
- return nil unless reference.respond_to?(:type_for_attribute)
74
-
75
- attribute_type = reference.type_for_attribute(name.to_s)
76
-
77
- return Granite::Action::Types::Collection.new(convert_type_to_value_class(attribute_type.subtype)) if attribute_type.respond_to?(:subtype)
78
-
79
- convert_type_to_value_class(attribute_type)
80
- end
81
-
82
- def convert_type_to_value_class(attribute_type)
83
- return attribute_type.value_class if attribute_type.respond_to?(:value_class)
84
-
85
- ActiveData::Model::Associations::PersistenceAdapters::ActiveRecord::TYPES[attribute_type.type&.to_sym]
86
- end
87
- end
88
- end
89
- end
90
- end
@@ -1,15 +0,0 @@
1
- require 'granite/action/represents/attribute'
2
-
3
- module Granite
4
- class Action
5
- module Represents
6
- class Reflection < ActiveData::Model::Attributes::Reflections::Represents
7
- class << self
8
- def attribute_class
9
- @attribute_class ||= Granite::Action::Represents::Attribute
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,39 +0,0 @@
1
- module Granite
2
- class Action
3
- module Translations
4
- extend ActiveSupport::Concern
5
-
6
- def translate(*args)
7
- I18n.translate(*self.class.scope_translation_args(args))
8
- end
9
- alias t translate
10
-
11
- module ClassMethods
12
- def scope_translation_args(args)
13
- options = args.extract_options!
14
-
15
- lookups = expand_relative_key(args.first).map(&:to_sym)
16
- lookups += [options[:default]]
17
- lookups = lookups.flatten.compact
18
-
19
- key = lookups.shift
20
- options[:default] = lookups
21
-
22
- [key, options]
23
- end
24
-
25
- private
26
-
27
- def expand_relative_key(key)
28
- return [key] unless key.is_a?(String) && key.start_with?('.')
29
-
30
- base_key = key.sub(/^\./, '')
31
-
32
- lookup_ancestors.map do |klass|
33
- :"#{klass.i18n_scope}.#{klass.model_name.i18n_key}.#{base_key}"
34
- end.flatten + [base_key]
35
- end
36
- end
37
- end
38
- end
39
- end