granite 0.7.0 → 0.8.0

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