golden-objects 0.1.0

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