granite 0.15.1 → 0.15.4

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: 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