golden-objects 0.1.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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/CHANGELOG.md +5 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +101 -0
  7. data/Rakefile +2 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/golden-objects.gemspec +32 -0
  11. data/lib/golden/active_model_concerns/datepicker_concern.rb +42 -0
  12. data/lib/golden/active_model_concerns/has_persisted_record_concern.rb +54 -0
  13. data/lib/golden/active_model_concerns/yaml_coder_concern.rb +44 -0
  14. data/lib/golden/active_model_concerns.rb +10 -0
  15. data/lib/golden/active_record_concerns/deleted_at_concern.rb +24 -0
  16. data/lib/golden/active_record_concerns/disabled_at_concern.rb +28 -0
  17. data/lib/golden/active_record_concerns/enum_value_concern.rb +27 -0
  18. data/lib/golden/active_record_concerns/rejected_at_concern.rb +24 -0
  19. data/lib/golden/active_record_concerns.rb +11 -0
  20. data/lib/golden/attribute_accessors/boolean_accessor.rb +34 -0
  21. data/lib/golden/attribute_accessors/date_time_accessor.rb +52 -0
  22. data/lib/golden/attribute_accessors/enum_accessor.rb +33 -0
  23. data/lib/golden/attribute_accessors/extended_attr_accessor.rb +53 -0
  24. data/lib/golden/attribute_accessors.rb +18 -0
  25. data/lib/golden/objects/application/application_calculator.rb +29 -0
  26. data/lib/golden/objects/application/application_context.rb +34 -0
  27. data/lib/golden/objects/application/application_form.rb +41 -0
  28. data/lib/golden/objects/application/application_generator.rb +18 -0
  29. data/lib/golden/objects/application/application_operator.rb +20 -0
  30. data/lib/golden/objects/application/application_presenter.rb +14 -0
  31. data/lib/golden/objects/application/application_service.rb +14 -0
  32. data/lib/golden/objects/application/application_transformer.rb +22 -0
  33. data/lib/golden/objects/form/action_form_operator.rb +84 -0
  34. data/lib/golden/objects/form/active_record_form.rb +35 -0
  35. data/lib/golden/objects/form/single_form_presenter.rb +40 -0
  36. data/lib/golden/objects/query/query_context.rb +114 -0
  37. data/lib/golden/objects/query/query_form.rb +59 -0
  38. data/lib/golden/objects/query/query_form_operator.rb +66 -0
  39. data/lib/golden/objects/query/query_result_presenter.rb +30 -0
  40. data/lib/golden/objects/version.rb +5 -0
  41. data/lib/golden/objects.rb +34 -0
  42. metadata +129 -0
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'golden/attribute_accessors/extended_attr_accessor'
4
+ require 'golden/attribute_accessors/boolean_accessor'
5
+ require 'golden/attribute_accessors/date_time_accessor'
6
+ require 'golden/attribute_accessors/enum_accessor'
7
+
8
+ module Golden
9
+ module AttributeAccessors
10
+ class << self
11
+ def default_zone
12
+ return ::Rails.application.config.time_zone if ::Object.const_defined? 'Rails'
13
+
14
+ 'UTC'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'golden/attribute_accessors'
4
+
5
+ module Golden
6
+ class ApplicationCalculator
7
+ include ActiveModel::AttributeAssignment
8
+ include ActiveModel::Validations
9
+ include Golden::BooleanAccessor
10
+
11
+ def initialize(accessors = {})
12
+ assign_attributes(accessors || {})
13
+ end
14
+
15
+ def perform
16
+ raise NotImplementedError
17
+ end
18
+
19
+ private
20
+
21
+ def parse_decimal(value)
22
+ return value.to_d if value.respond_to? :to_d
23
+
24
+ BigDecimal(value.presence || 0)
25
+ rescue ArgumentError
26
+ BigDecimal(0)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'golden/attribute_accessors'
4
+
5
+ module Golden
6
+ class ApplicationContext
7
+ class << self
8
+ def attributes
9
+ accessor_attributes
10
+ end
11
+
12
+ def permits
13
+ @permits ||= lambda do
14
+ attrs = attributes.clone
15
+ attrs
16
+ end.call
17
+ end
18
+ end
19
+
20
+ include ActiveModel::AttributeAssignment
21
+ include ActiveModel::Validations
22
+ include Golden::ExtendedAttrAccessor
23
+ include Golden::BooleanAccessor
24
+ include Golden::DateTimeAccessor
25
+
26
+ def initialize(accessors = {})
27
+ assign_attributes(accessors || {})
28
+ end
29
+
30
+ def perform
31
+ raise NotImplementedError
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'golden/attribute_accessors'
4
+ require 'golden/active_model_concerns'
5
+
6
+ module Golden
7
+ class ApplicationForm
8
+ class << self
9
+ def attributes
10
+ accessor_attributes
11
+ end
12
+
13
+ def permits
14
+ @permits ||= lambda do
15
+ attrs = attributes.clone
16
+ attrs
17
+ end.call
18
+ end
19
+ end
20
+
21
+ extend ActiveModel::Callbacks
22
+ include ActiveModel::AttributeAssignment
23
+ include ActiveModel::Validations
24
+ include ActiveModel::Validations::Callbacks
25
+ include ActiveModel::Conversion
26
+ include Golden::ExtendedAttrAccessor
27
+ include Golden::BooleanAccessor
28
+ include Golden::DateTimeAccessor
29
+ include Golden::EnumAccessor
30
+
31
+ define_model_callbacks :save
32
+
33
+ def initialize(accessors = {})
34
+ assign_attributes(strip_attributes(accessors || {}))
35
+ end
36
+
37
+ def save
38
+ raise NotImplementedError
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'golden/attribute_accessors'
4
+
5
+ module Golden
6
+ class ApplicationGenerator
7
+ include ActiveModel::AttributeAssignment
8
+ include ActiveModel::Validations
9
+
10
+ def initialize(accessors = {})
11
+ assign_attributes(accessors || {})
12
+ end
13
+
14
+ def perform
15
+ raise NotImplementedError
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'golden/attribute_accessors'
4
+
5
+ module Golden
6
+ class ApplicationOperator
7
+ include ActiveModel::AttributeAssignment
8
+ include ActiveModel::Validations
9
+ include ActiveModel::Validations::Callbacks
10
+ include Golden::DatepickerConcern
11
+
12
+ def initialize(accessors = {})
13
+ assign_attributes(accessors || {})
14
+ end
15
+
16
+ def perform
17
+ raise NotImplementedError
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'golden/attribute_accessors'
4
+
5
+ module Golden
6
+ class ApplicationPresenter
7
+ extend ActiveModel::Translation
8
+ include ActiveModel::AttributeAssignment
9
+
10
+ def initialize(accessors = {})
11
+ assign_attributes(accessors || {})
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'golden/attribute_accessors'
4
+
5
+ module Golden
6
+ class ApplicationService
7
+ include ActiveModel::Validations
8
+ include ActiveModel::Validations::Callbacks
9
+
10
+ def run
11
+ raise NotImplementedError
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'golden/attribute_accessors'
4
+
5
+ module Golden
6
+ class ApplicationTransformer
7
+ include ActiveModel::AttributeAssignment
8
+ include ActiveModel::Validations
9
+ include ActiveModel::Validations::Callbacks
10
+ include Golden::BooleanAccessor
11
+ include Golden::DateTimeAccessor
12
+
13
+ def initialize(params, accessors = {})
14
+ @params = params
15
+ assign_attributes(accessors || {})
16
+ end
17
+
18
+ def perform
19
+ raise NotImplementedError
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Golden
4
+ class ActionFormOperator < Golden::ApplicationOperator
5
+ class << self
6
+ # rubocop:disable Naming/PredicateName
7
+ def has_actions(actions, form: nil, presenter: nil)
8
+ define_method :actions do
9
+ actions
10
+ end
11
+
12
+ define_method :form_class do
13
+ return form.to_s.constantize if form.present?
14
+
15
+ "#{action.capitalize}Form".constantize
16
+ end
17
+
18
+ define_method :presenter_class do
19
+ return presenter.to_s.constantize if presenter.present?
20
+
21
+ "#{action.capitalize}FormPresenter".constantize
22
+ end
23
+ end
24
+ # rubocop:enable Naming/PredicateName
25
+ end
26
+
27
+ extend ActiveModel::Callbacks
28
+
29
+ attr_accessor :user, :form
30
+ attr_accessor :params, :action
31
+
32
+ validates :action, presence: true
33
+ validates :form, presence: true
34
+
35
+ define_model_callbacks :build_form
36
+ define_model_callbacks :validate_form
37
+ define_model_callbacks :save_form
38
+
39
+ def initialize(params, accessors = {})
40
+ @params = params
41
+ @action = params[:action]&.to_sym
42
+ assign_attributes(accessors || {})
43
+ run_callbacks(:build_form) { @form ||= build_form }
44
+ end
45
+
46
+ def valid?(context = nil)
47
+ super
48
+ run_callbacks(:validate_form) { validate_form }
49
+ errors.empty?
50
+ end
51
+
52
+ def perform
53
+ return if invalid?
54
+
55
+ run_callbacks(:save_form) { save_form }
56
+ errors.empty?
57
+ end
58
+
59
+ def form_presenter
60
+ @form_presenter ||= presenter_class.new(form)
61
+ end
62
+
63
+ private
64
+
65
+ def build_form
66
+ return if action.blank? || actions.exclude?(action)
67
+
68
+ form_params = send("#{action}_params")
69
+ form_accessors = send("#{action}_accessors") if private_methods.include? :"#{action}_accessors"
70
+ form_class.new form_params.permit(*form_class.permits), form_accessors
71
+ end
72
+
73
+ def validate_form
74
+ return unless form.present? && form.invalid?
75
+
76
+ errors.merge! form.errors
77
+ end
78
+
79
+ def save_form
80
+ form.save
81
+ errors.merge! form.errors
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Golden
4
+ class ActiveRecordForm < Golden::ApplicationForm
5
+ def initialize(params, accessors = {})
6
+ assign_attributes(strip_attributes(params))
7
+ assign_attributes(strip_attributes(accessors || {}))
8
+ end
9
+
10
+ def save
11
+ return false if invalid?
12
+
13
+ ::ActiveRecord::Base.transaction do
14
+ run_callbacks(:save) { persist! }
15
+ end
16
+ errors.empty?
17
+ end
18
+
19
+ private
20
+
21
+ def persist!
22
+ raise NotImplementedError, <<~ERROR
23
+ Please define #{__method__} like
24
+ ```
25
+ def #{__method__}
26
+ return true if @order.save
27
+
28
+ errors.merge! @order.errors
29
+ false
30
+ end
31
+ ```
32
+ ERROR
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Golden
4
+ class SingleFormPresenter < Golden::ApplicationPresenter
5
+ class << self
6
+ def form_accessors(permits)
7
+ accessors = permits.reject do |permit|
8
+ %w[Symbol String].exclude? permit.class.name
9
+ end
10
+ attr_accessor(*accessors)
11
+ end
12
+ end
13
+
14
+ # include Rails.application.routes.url_helpers
15
+
16
+ attr_reader :form
17
+
18
+ delegate :errors, :valid?, to: :form
19
+
20
+ def initialize(form, accessors = {})
21
+ assign_form_attributes(form, excludes: excluded_form_accessors)
22
+ assign_attributes(accessors || {})
23
+ end
24
+
25
+ def assign_form_attributes(form, excludes: [])
26
+ @form = form
27
+ accessors = form.class.permits.reject { |permit| excludes.include?(permit) }
28
+ self.class.form_accessors accessors
29
+ assign_attributes form.attributes.slice(*accessors)
30
+ end
31
+
32
+ def excluded_form_accessors
33
+ []
34
+ end
35
+
36
+ def persisted?
37
+ false
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Golden
4
+ class QueryContext < Golden::ApplicationContext
5
+ class << self
6
+ def attributes
7
+ merge_attributes!(:sort)
8
+ accessor_attributes
9
+ end
10
+ end
11
+
12
+ attr_accessor :page, :per
13
+ attr_accessor :sort_field, :sort_direction
14
+
15
+ def initialize(accessors = {})
16
+ assign_attributes(accessors || {})
17
+ @page ||= 1
18
+ @per ||= 100
19
+ end
20
+
21
+ def perform(mode = :paginated)
22
+ send("find_#{mode}")
23
+ end
24
+
25
+ def sort=(values)
26
+ return if values.blank?
27
+
28
+ field, direction = values.to_s.split(',')
29
+ @sort_field = field.presence&.to_sym
30
+ @sort_direction = direction.presence&.to_sym
31
+ end
32
+
33
+ private
34
+
35
+ def find_first
36
+ return nil if invalid?
37
+
38
+ relations.where(query_scopes).order(sort).first
39
+ end
40
+
41
+ def find_last
42
+ return nil if invalid?
43
+
44
+ relations.where(query_scopes).order(sort).last
45
+ end
46
+
47
+ def find_all
48
+ return [] if invalid?
49
+
50
+ relations.where(query_scopes).order(sort).all
51
+ end
52
+
53
+ def find_count
54
+ return nil if invalid?
55
+
56
+ relations.where(query_scopes).order(sort).count
57
+ end
58
+
59
+ def find_paginated
60
+ return paginated_blank_result if invalid?
61
+
62
+ relations.where(query_scopes).order(sort).page(page).per(per)
63
+ end
64
+
65
+ def paginated_blank_result
66
+ return Kaminari.paginate_array([], total_count: 0).page(1) if ::Object.const_defined? 'Kaminari'
67
+
68
+ raise NotImplementedError
69
+ end
70
+
71
+ def relations
72
+ raise NotImplementedError, <<~ERROR
73
+ Please define #{__method__} like
74
+ ```
75
+ def #{__method__}
76
+ @#{__method__} ||= Record.joins().includes().eager_load()
77
+ end
78
+ ```
79
+ ERROR
80
+ end
81
+
82
+ def sort
83
+ raise NotImplementedError, <<~ERROR
84
+ Please define #{__method__} like
85
+ ```
86
+ def #{__method__}
87
+ @sort_field ||= :id
88
+ @sort_direction ||= :desc
89
+ @#{__method__} ||= Record.arel_table[@sort_field].send(@sort_direction)
90
+ end
91
+ ```
92
+ ERROR
93
+ end
94
+
95
+ def query_scopes
96
+ raise NotImplementedError, <<~ERROR
97
+ Please define #{__method__} like
98
+ ```
99
+ def #{__method__}
100
+ concat_xxx_scope
101
+ @scopes
102
+ end
103
+ ```
104
+ And define concat_xxx_scope like
105
+ ```
106
+ def concat_xxx_scope
107
+ scope = Record.arel_table[:xxx_number].eq(@xxx_number)
108
+ @scopes = @scopes ? @scopes.and(scope) : scope
109
+ end
110
+ ```
111
+ ERROR
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Golden
4
+ class QueryForm < Golden::ApplicationForm
5
+ class << self
6
+ def attributes
7
+ accessor_attributes
8
+ end
9
+
10
+ def permits
11
+ @permits ||= lambda do
12
+ attrs = attributes.clone
13
+ attrs.uniq
14
+ end.call
15
+ end
16
+ end
17
+
18
+ attr_reader :result
19
+ attr_accessor :per, :page, :sort
20
+
21
+ def initialize(params, accessors = {})
22
+ @query_params = find_query_from(params)
23
+ assign_attributes(strip_attributes(@query_params))
24
+ assign_attributes(strip_attributes(accessors || {}))
25
+ @per ||= params.dig(:per)
26
+ @page ||= params.dig(:page)
27
+ @sort ||= params.dig(:sort)
28
+ end
29
+
30
+ def save
31
+ return false if invalid?
32
+
33
+ query!
34
+ errors.empty?
35
+ end
36
+
37
+ private
38
+
39
+ def find_query_from(params)
40
+ if ::Object.const_defined?('ActionController') && params.is_a?(ActionController::Parameters)
41
+ params.require(:query).permit(*self.class.permits)
42
+ else
43
+ params.dig(:query)&.slice(*self.class.permits) || {}
44
+ end
45
+ rescue ActionController::ParameterMissing
46
+ {}
47
+ end
48
+
49
+ def query_accessors
50
+ attrs = attributes.clone
51
+ attrs.each { |accessor, value| attrs.delete(accessor) if value.blank? }
52
+ attrs
53
+ end
54
+
55
+ def query!
56
+ raise NotImplementedError
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Golden
4
+ class QueryFormOperator < Golden::ApplicationOperator
5
+ class << self
6
+ # rubocop:disable Naming/PredicateName
7
+ def has_query_form(form: nil, form_presenter: nil, result_presenter: nil)
8
+ define_method :form_class do
9
+ return form.to_s.constantize if form.present?
10
+
11
+ "#{self.class.parent.name}::QueryForm".constantize
12
+ end
13
+
14
+ define_method :form_presenter_class do
15
+ return form_presenter.to_s.constantize if form_presenter.present?
16
+
17
+ "#{self.class.parent.name}::QueryFormPresenter".constantize
18
+ end
19
+
20
+ define_method :result_presenter_class do
21
+ return result_presenter.to_s.constantize if result_presenter.present?
22
+
23
+ "#{self.class.parent.name}::QueryResultPresenter".constantize
24
+ end
25
+ end
26
+ # rubocop:enable Naming/PredicateName
27
+ end
28
+
29
+ extend ActiveModel::Callbacks
30
+
31
+ define_model_callbacks :build_form
32
+
33
+ attr_reader :params, :form
34
+
35
+ def initialize(params, accessors = {})
36
+ @params = params
37
+ assign_attributes(accessors || {})
38
+ run_callbacks(:build_form) { @form ||= build_form }
39
+ end
40
+
41
+ def perform
42
+ form.save
43
+ errors.merge! form.errors
44
+ errors.empty?
45
+ end
46
+
47
+ def form_presenter
48
+ @form_presenter ||= form_presenter_class.new form
49
+ end
50
+
51
+ def result_presenter
52
+ @result_presenter ||= result_presenter_class.collect form.result
53
+ end
54
+
55
+ private
56
+
57
+ def query_params
58
+ params
59
+ end
60
+
61
+ def build_form
62
+ form_accessors = send(:query_accessors) if private_methods.include? :query_accessors
63
+ form_class.new query_params, form_accessors
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Golden
4
+ class QueryResultPresenter < Golden::ApplicationPresenter
5
+ include Enumerable
6
+
7
+ attr_reader :records, :presenters
8
+
9
+ def initialize(records, presenter_class)
10
+ @records = records
11
+ @presenters = records.map { |record| presenter_class.constantize.new record }
12
+ end
13
+
14
+ def each(&block)
15
+ presenters.each(&block)
16
+ end
17
+
18
+ def total_count
19
+ records.total_count
20
+ end
21
+
22
+ def current_page
23
+ records.current_page
24
+ end
25
+
26
+ def per_page
27
+ records.limit_value
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ module Golden
2
+ module Objects
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_model'
5
+ require 'active_record'
6
+
7
+ require 'golden/objects/version'
8
+ require 'golden/attribute_accessors'
9
+ require 'golden/active_model_concerns'
10
+ require 'golden/active_record_concerns'
11
+
12
+ require 'golden/objects/application/application_calculator'
13
+ require 'golden/objects/application/application_context'
14
+ require 'golden/objects/application/application_form'
15
+ require 'golden/objects/application/application_generator'
16
+ require 'golden/objects/application/application_operator'
17
+ require 'golden/objects/application/application_presenter'
18
+ require 'golden/objects/application/application_service'
19
+ require 'golden/objects/application/application_transformer'
20
+
21
+ require 'golden/objects/form/action_form_operator'
22
+ require 'golden/objects/form/active_record_form'
23
+ require 'golden/objects/form/single_form_presenter'
24
+
25
+ require 'golden/objects/query/query_context'
26
+ require 'golden/objects/query/query_form'
27
+ require 'golden/objects/query/query_form_operator'
28
+ require 'golden/objects/query/query_result_presenter'
29
+
30
+ module Golden
31
+ module Objects
32
+ class Error < StandardError; end
33
+ end
34
+ end