granite 0.15.1 → 0.15.4

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
  SHA256:
3
- metadata.gz: d0a4953c8a4a24dfab614a8831bb8b39cda81d4a0b2d7e3ea8f2bb5d3d8eccc4
4
- data.tar.gz: 6f1655c4167aef595d7c36fcd0fbde9e72376bd1fec2dafc38e6dc508f4f0417
3
+ metadata.gz: b2c26504cf64e66471237d5e225ec9a764c97a7d0a7e4fe70506b707402fb758
4
+ data.tar.gz: 1a4e0f6d7713d2d3c2c3f8b4a0651c3a42aeb60bdc0057a92ebae516c7bf8cab
5
5
  SHA512:
6
- metadata.gz: bd0b0f97527283426bdaf8f5d25cf033053f0636958578621c84f5c8fc0c01f70528f1d759213ac0cddbc3327d5b06951b231d18cce3e987c612697dabb90c89
7
- data.tar.gz: deff30290527973e4dee79d4584c7ffd5090a80737da57d1efe48e8fcdd89d0e11d220c8b5c81b55f313f2d3ced81b097ab454c67065b6db458629e18924c236
6
+ metadata.gz: 4385e90e1084b85136a23a6b441ce2f22ec709658ac70c4459bf178ec8de9145666886fececfcbb18d846e8edb28260f2c43313fd2f2e209a37fa22035074046
7
+ data.tar.gz: 59b8b496841fbc135f11ccba324bc45036a85f808f3340b045ef5b92aa3cd72cfc43bd0e5c8e68740c866a6b4102dfbff6ba4ea078baee0ad214eef169f9b9c4
@@ -5,11 +5,11 @@ class GraniteGenerator < Rails::Generators::NamedBase
5
5
  class_option :collection, type: :boolean, aliases: '-C', desc: 'Generate collection action'
6
6
 
7
7
  def create_action
8
- template 'granite_action.rb.erb', "apq/actions/#{file_path}.rb"
9
- template 'granite_business_action.rb.erb', "apq/actions/#{class_path.join('/')}/business_action.rb" unless options.collection?
8
+ template 'granite_action.rb.erb', "apq/actions/ba/#{file_path}.rb"
9
+ template 'granite_business_action.rb.erb', "apq/actions/ba/#{class_path.join('/')}/business_action.rb" unless options.collection?
10
10
  template 'granite_base_action.rb.erb', 'apq/actions/base_action.rb', skip: true
11
- template 'granite_action_spec.rb.erb', "spec/apq/actions/#{file_path}_spec.rb"
12
- empty_directory "apq/actions/#{file_path}/#{projector}" if projector
11
+ template 'granite_action_spec.rb.erb', "spec/apq/actions/ba/#{file_path}_spec.rb"
12
+ empty_directory "apq/actions/ba/#{file_path}/#{projector}" if projector
13
13
  end
14
14
 
15
15
  private
@@ -18,7 +18,7 @@ class GraniteGenerator < Rails::Generators::NamedBase
18
18
  if options.collection?
19
19
  'BaseAction'
20
20
  else
21
- "#{class_path.join('/').camelize}::BusinessAction"
21
+ "BA::#{class_path.join('/').camelize}::BusinessAction"
22
22
  end
23
23
  end
24
24
 
@@ -1,4 +1,4 @@
1
- class <%= class_name %> < <%= base_class_name %>
1
+ class BA::<%= class_name %> < <%= base_class_name %>
2
2
  <% if projector -%>
3
3
  projector :<%= projector %>
4
4
 
@@ -1,6 +1,6 @@
1
1
  require 'rails_helper'
2
2
 
3
- RSpec.describe <%= class_name %> do
3
+ RSpec.describe BA::<%= class_name %> do
4
4
  <% if options.collection? -%>
5
5
  subject(:action) { described_class.as(performer).new(attributes) }
6
6
 
@@ -1,3 +1,3 @@
1
- class <%= class_path.join('/').camelize %>::BusinessAction < BaseAction
1
+ class BA::<%= class_path.join('/').camelize %>::BusinessAction < BaseAction
2
2
  subject :<%= subject_name %>
3
3
  end
@@ -93,6 +93,7 @@ module Granite
93
93
 
94
94
  def perform_action(raise_errors: false, **options)
95
95
  result = run_callbacks(:execute_perform) do
96
+ apply_association_changes!
96
97
  execute_perform!(**options)
97
98
  end
98
99
  @_action_performed = true
@@ -36,10 +36,10 @@ module Granite
36
36
 
37
37
  private
38
38
 
39
- attr_accessor :in_transaction
39
+ attr_accessor :granite_in_transaction
40
40
 
41
41
  def transaction(&block)
42
- if in_transaction
42
+ if granite_in_transaction
43
43
  yield
44
44
  else
45
45
  run_in_transaction(&block)
@@ -47,14 +47,14 @@ module Granite
47
47
  end
48
48
 
49
49
  def run_in_transaction
50
- self.in_transaction = true
50
+ self.granite_in_transaction = true
51
51
 
52
52
  TransactionManager.transaction do
53
53
  TransactionManager.after_commit(self)
54
54
  yield
55
55
  end
56
56
  ensure
57
- self.in_transaction = false
57
+ self.granite_in_transaction = false
58
58
  end
59
59
  end
60
60
  end
@@ -2,18 +2,10 @@ module Granite
2
2
  class Action
3
3
  module Types
4
4
  class Collection
5
- attr_reader :subtype_definition
5
+ attr_reader :subtype
6
6
 
7
- def initialize(subtype_definition)
8
- @subtype_definition = subtype_definition
9
- end
10
-
11
- def ensure_type(value)
12
- if value.respond_to? :transform_values
13
- value.transform_values { |v| subtype_definition.ensure_type(v) }
14
- elsif value.respond_to?(:map)
15
- value.map { |v| subtype_definition.ensure_type(v) }
16
- end
7
+ def initialize(subtype)
8
+ @subtype = subtype
17
9
  end
18
10
  end
19
11
  end
data/lib/granite/base.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'granite/form/model'
2
2
  require 'granite/form/model/primary'
3
+ require 'granite/form/model/lifecycle'
3
4
  require 'granite/form/model/associations'
4
5
 
5
6
  require 'granite/translations'
@@ -4,11 +4,6 @@ module Granite
4
4
  types = {}
5
5
  types[ActiveRecord::Enum::EnumType] = String if defined?(ActiveRecord)
6
6
  TYPES = types.freeze
7
- GRANITE_COLLECTION_TYPES = [
8
- Granite::Form::Model::Attributes::ReferenceMany,
9
- Granite::Form::Model::Attributes::Collection,
10
- Granite::Form::Model::Attributes::Dictionary
11
- ].freeze
12
7
  delegate :writer, :reader, :reader_before_type_cast, to: :reflection
13
8
 
14
9
  def initialize(*_args)
@@ -22,12 +17,23 @@ module Granite
22
17
  reference.public_send(writer, read) if reference.respond_to?(writer)
23
18
  end
24
19
 
25
- def type_definition
26
- @type_definition ||= if reflection.options[:type].present?
27
- build_type_definition(reflection.options[:type])
28
- else
29
- granite_form_type_definition || active_record_type_definition || super
30
- end
20
+ def typecast(value)
21
+ return value if value.class == type # rubocop:disable Style/ClassEqualityComparison
22
+
23
+ typecaster.call(value, self) unless value.nil?
24
+ end
25
+
26
+ def type
27
+ return reflection.options[:type] if reflection.options[:type].present?
28
+
29
+ granite_form_type || type_from_type_for_attribute || super
30
+ end
31
+
32
+ def typecaster
33
+ @typecaster ||= begin
34
+ type_class = type.instance_of?(Class) ? type : type.class
35
+ @typecaster = Granite::Form.typecaster(type_class.ancestors.grep(Class))
36
+ end
31
37
  end
32
38
 
33
39
  def changed?
@@ -48,7 +54,7 @@ module Granite
48
54
  return unless reference.respond_to?(reader)
49
55
 
50
56
  variable_cache(:value) do
51
- normalize(enumerize(type_definition.ensure_type(defaultize(reference.public_send(reader)))))
57
+ normalize(enumerize(typecast(defaultize(reference.public_send(reader)))))
52
58
  end
53
59
  end
54
60
 
@@ -60,33 +66,31 @@ module Granite
60
66
  end
61
67
  end
62
68
 
63
- def granite_form_type_definition
69
+ def granite_form_type
64
70
  return nil unless reference.is_a?(Granite::Form::Model)
65
71
 
66
72
  reference_attribute = reference.attribute(name)
67
73
 
68
74
  return nil if reference_attribute.nil?
69
75
 
70
- type_definition = build_type_definition(reference_attribute.type)
71
- if GRANITE_COLLECTION_TYPES.any? { |klass| reference_attribute.is_a? klass }
72
- Granite::Action::Types::Collection.new(type_definition)
73
- else
74
- type_definition
75
- end
76
+ return Granite::Action::Types::Collection.new(reference_attribute.type) if [
77
+ Granite::Form::Model::Attributes::ReferenceMany,
78
+ Granite::Form::Model::Attributes::Collection,
79
+ Granite::Form::Model::Attributes::Dictionary
80
+ ].any? { |klass| reference_attribute.is_a? klass }
81
+
82
+ reference_attribute.type # TODO: create `type_for_attribute` method inside of Granite::Form
76
83
  end
77
84
 
78
- def active_record_type_definition
85
+ def type_from_type_for_attribute
79
86
  return nil unless reference.respond_to?(:type_for_attribute)
80
87
 
81
88
  attribute_type = reference.type_for_attribute(attribute_name.to_s)
82
89
 
83
- if TYPES.key?(attribute_type.class)
84
- build_type_definition(TYPES[attribute_type.class])
85
- elsif attribute_type.respond_to?(:subtype)
86
- Granite::Action::Types::Collection.new(convert_active_model_type_to_definition(attribute_type.subtype))
87
- else
88
- convert_active_model_type_to_definition(attribute_type)
89
- end
90
+ return TYPES[attribute_type.class] if TYPES.key?(attribute_type.class)
91
+ return Granite::Action::Types::Collection.new(convert_type_to_value_class(attribute_type.subtype)) if attribute_type.respond_to?(:subtype)
92
+
93
+ convert_type_to_value_class(attribute_type)
90
94
  end
91
95
 
92
96
  def attribute_name
@@ -95,10 +99,10 @@ module Granite
95
99
  reference.class.attribute_aliases[name.to_s] || name
96
100
  end
97
101
 
98
- def convert_active_model_type_to_definition(attribute_type)
99
- type = attribute_type.try(:value_class) ||
100
- Form::Model::Associations::PersistenceAdapters::ActiveRecord::TYPES[attribute_type.type&.to_sym]
101
- build_type_definition(type) if type
102
+ def convert_type_to_value_class(attribute_type)
103
+ return attribute_type.value_class if attribute_type.respond_to?(:value_class)
104
+
105
+ Granite::Form::Model::Associations::PersistenceAdapters::ActiveRecord::TYPES[attribute_type.type&.to_sym]
102
106
  end
103
107
  end
104
108
  end
@@ -0,0 +1,10 @@
1
+ require 'granite/form'
2
+
3
+ Granite::Form.typecaster('Granite::Action::Types::Collection') do |value, attribute|
4
+ typecaster = Granite::Form.typecaster(attribute.type.subtype)
5
+ if value.respond_to? :transform_values
6
+ value.transform_values { |v| typecaster.call(v, attribute) }
7
+ elsif value.respond_to?(:map)
8
+ value.map { |v| typecaster.call(v, attribute) }
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module Granite
2
- VERSION = '0.15.1'.freeze
2
+ VERSION = '0.15.4'.freeze
3
3
  end
data/lib/granite.rb CHANGED
@@ -25,6 +25,7 @@ require 'granite/dispatcher'
25
25
  require 'granite/action'
26
26
  require 'granite/projector'
27
27
  require 'granite/routing'
28
- require 'granite/rails' if defined?(Rails)
28
+ require 'granite/typecasters'
29
+ require 'granite/rails' if defined?(::Rails)
29
30
 
30
31
  Granite::Form.base_concern = Granite::Base
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.15.1
4
+ version: 0.15.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toptal Engineering
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-02 00:00:00.000000000 Z
11
+ date: 2024-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -36,14 +36,14 @@ dependencies:
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: 0.3.0
39
+ version: '0'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 0.3.0
46
+ version: '0'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: activesupport
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -120,20 +120,6 @@ dependencies:
120
120
  - - ">="
121
121
  - !ruby/object:Gem::Version
122
122
  version: '0'
123
- - !ruby/object:Gem::Dependency
124
- name: bump
125
- requirement: !ruby/object:Gem::Requirement
126
- requirements:
127
- - - ">="
128
- - !ruby/object:Gem::Version
129
- version: '0'
130
- type: :development
131
- prerelease: false
132
- version_requirements: !ruby/object:Gem::Requirement
133
- requirements:
134
- - - ">="
135
- - !ruby/object:Gem::Version
136
- version: '0'
137
123
  - !ruby/object:Gem::Dependency
138
124
  name: capybara
139
125
  requirement: !ruby/object:Gem::Requirement
@@ -404,6 +390,7 @@ files:
404
390
  - lib/granite/rspec/raise_validation_error.rb
405
391
  - lib/granite/rspec/satisfy_preconditions.rb
406
392
  - lib/granite/translations.rb
393
+ - lib/granite/typecasters.rb
407
394
  - lib/granite/util.rb
408
395
  - lib/granite/version.rb
409
396
  - lib/rubocop-granite.rb
@@ -428,7 +415,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
428
415
  - !ruby/object:Gem::Version
429
416
  version: '0'
430
417
  requirements: []
431
- rubygems_version: 3.3.26
418
+ rubygems_version: 3.1.6
432
419
  signing_key:
433
420
  specification_version: 4
434
421
  summary: Another business actions architecture for Rails apps