formalism-model_forms 0.6.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 65944c5d862966df0531c80ae45d603e01bd8a576983a5ad180e75c29f9116e6
4
+ data.tar.gz: eedd373f63d2e6b4dc2da93c896fa9ebdf65a0e172a8c2794f5497abe622195f
5
+ SHA512:
6
+ metadata.gz: 5580e66079f5f4fafa3819a0fe9bb0a8825819bd2daacf5da932689e5123748be187613fd7bc9d3e01b285f7ffa952ad7602980705efa3987e75dcca9954db75
7
+ data.tar.gz: e2b511cb8a47a70018fa55af7a2a0807d51429740ebf243edd203826751316a6ae500b3e3f709e6df370b1ffe3928bd3987341725af428e5911a15e31acea22e
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ ## master (unreleased)
4
+
5
+ ## 0.6.0 (2020-09-23)
6
+
7
+ ## 0.5.0 (2020-09-22)
8
+
9
+ * Require `forwardable` before its usage.
10
+
11
+ ## 0.4.0 (2020-07-10)
12
+
13
+ * Remove `puts` about `define_for_project` steps
14
+
15
+ ## 0.3.0 (2020-07-10)
16
+
17
+ * Remove debug actions
18
+
19
+ ## 0.2.0 (2020-07-10)
20
+
21
+ * Update `flame-pagination` to version `0.3.0`, which allows Flame version 5.
22
+
23
+ ## 0.1.0 (2020-07-10)
24
+
25
+ * Initial release.
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Alexander Popov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,100 @@
1
+ # Formalism Model Forms
2
+
3
+ [![Cirrus CI - Base Branch Build Status](https://img.shields.io/cirrus/github/AlexWayfer/formalism-model_forms?style=flat-square)](https://cirrus-ci.com/github/AlexWayfer/formalism-model_forms)
4
+ [![Codecov branch](https://img.shields.io/codecov/c/github/AlexWayfer/formalism-model_forms/master.svg?style=flat-square)](https://codecov.io/gh/AlexWayfer/formalism-model_forms)
5
+ [![Code Climate](https://img.shields.io/codeclimate/maintainability/AlexWayfer/formalism-model_forms.svg?style=flat-square)](https://codeclimate.com/github/AlexWayfer/formalism-model_forms)
6
+ [![Depfu](https://img.shields.io/depfu/AlexWayfer/benchmark_toys?style=flat-square)](https://depfu.com/repos/github/AlexWayfer/formalism-model_forms)
7
+ [![Inline docs](https://inch-ci.org/github/AlexWayfer/formalism-model_forms.svg?branch=master)](https://inch-ci.org/github/AlexWayfer/formalism-model_forms)
8
+ [![License](https://img.shields.io/github/license/AlexWayfer/formalism-model_forms.svg?style=flat-square)](LICENSE.txt)
9
+ [![Gem](https://img.shields.io/gem/v/formalism-model_forms.svg?style=flat-square)](https://rubygems.org/gems/formalism-model_forms)
10
+
11
+ Ruby gem with standard [Formalism](https://github.com/AlexWayfer/formalism) forms
12
+ for ([Sequel](https://sequel.jeremyevans.net/)) models.
13
+ Used by [Flame Generate Toys](https://github.com/AlexWayfer/flame_generate_toys).
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'formalism-model_forms'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ ```shell
26
+ bundle install
27
+ ```
28
+
29
+ Or install it yourself as:
30
+
31
+ ```shell
32
+ gem install formalism-model_forms
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ```ruby
38
+ # forms/_base.rb
39
+
40
+ require 'formalism/model_forms'
41
+
42
+ ## Define base form and model forms via gem
43
+ module MyProject
44
+ module Forms
45
+ ## Base class for forms
46
+ class Base < Formalism::Form
47
+ end
48
+ end
49
+
50
+ Formalism::ModelForms.define_for_project self
51
+ end
52
+ ```
53
+
54
+ `.define_for_project` requires project namespace (`self` in the example above)
55
+ and allows such options:
56
+
57
+ * `:forms_namespace`, default is `project_namespace::Forms`
58
+ * `:models_namespace`, default is `project_namespace::Models`
59
+
60
+ ```ruby
61
+ # forms/user/create.rb
62
+
63
+ module MyProject
64
+ module Forms
65
+ module User
66
+ class Create < Formalism::ModelForms::Create
67
+ field :name
68
+
69
+ private
70
+
71
+ def validate
72
+ errors.add 'Name is not provided' if name.to_s.empty?
73
+ end
74
+
75
+ # `execute` is inherited from `Formalism::ModelForms`
76
+ end
77
+ end
78
+ end
79
+ end
80
+ ```
81
+
82
+ ## Development
83
+
84
+ After checking out the repo, run `bundle install` to install dependencies.
85
+
86
+ Then, run `toys rspec` to run the tests.
87
+
88
+ To install this gem onto your local machine, run `toys gem install`.
89
+
90
+ To release a new version, run `toys gem release %version%`.
91
+ See how it works [here](https://github.com/AlexWayfer/gem_toys#release).
92
+
93
+ ## Contributing
94
+
95
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/AlexWayfer/formalism).
96
+
97
+ ## License
98
+
99
+ The gem is available as open source under the terms of the
100
+ [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'formalism'
4
+ require 'module_methods'
5
+
6
+ Dir["#{__dir__}/model_forms/**/*.rb"].sort.each { |file| require file }
7
+
8
+ module Formalism
9
+ ## Module for model forms
10
+ module ModelForms
11
+ class << self
12
+ def define_for_project(
13
+ project_namespace,
14
+ forms_namespace: project_namespace::Forms,
15
+ models_namespace: (project_namespace::Models if project_namespace.const_defined?(:Models))
16
+ )
17
+ forms_namespace.const_set :Model, Module.new
18
+
19
+ define_model_base_form forms_namespace, models_namespace
20
+
21
+ define_other_model_forms forms_namespace
22
+ end
23
+
24
+ private
25
+
26
+ def define_model_base_form(forms_namespace, models_namespace)
27
+ forms_namespace::Model.const_set :Base, (Class.new(forms_namespace::Base) do
28
+ include ModelForms::Base
29
+
30
+ const_set :FORMS_NAMESPACE, forms_namespace
31
+ const_set :MODELS_NAMESPACE, models_namespace
32
+ end)
33
+ end
34
+
35
+ FORM_CLASSES =
36
+ %i[Create Delete Find FindOrCreate List Move Update]
37
+ .map { |name| [name, :Base] }
38
+ .push(%i[Select Find])
39
+ .to_h
40
+ .freeze
41
+
42
+ def define_other_model_forms(forms_namespace)
43
+ FORM_CLASSES.each do |form_name, parent_name|
44
+ forms_namespace::Model.class_eval(
45
+ <<~CODE,
46
+ class #{form_name} < #{forms_namespace}::Model::#{parent_name}
47
+ include ModelForms::#{form_name}
48
+ end
49
+ CODE
50
+ __FILE__, __LINE__ - 4
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'gorilla_patch/inflections'
5
+ require 'gorilla_patch/namespace'
6
+ require 'memery'
7
+ require 'sequel'
8
+
9
+ module Formalism
10
+ module ModelForms
11
+ ## Base form for models
12
+ module Base
13
+ extend ::ModuleMethods::Extension
14
+ include Formalism::Form::Fields
15
+
16
+ # TODO: Check
17
+ extend Forwardable
18
+ def_delegators(
19
+ 'self.class',
20
+ :namespace, :model_name, :model, :instance_variable_name
21
+ )
22
+
23
+ ## Module for Base form class methods
24
+ module ClassMethods
25
+ include Memery
26
+
27
+ def inherited(form)
28
+ super
29
+
30
+ return if form.instance_name == :model
31
+ return if form.method_defined?(form.instance_name.to_s)
32
+
33
+ form.alias_method form.instance_name, :instance
34
+ form.alias_method "#{form.instance_name}=", :instance=
35
+ end
36
+
37
+ using GorillaPatch::Namespace
38
+ using GorillaPatch::Inflections
39
+
40
+ memoize def namespace
41
+ self::FORMS_NAMESPACE.const_get(deconstantize)
42
+ end
43
+
44
+ memoize def model_name
45
+ deconstantize.split('::')[2..-1].reverse
46
+ .find { |part| self::MODELS_NAMESPACE.const_defined?(part, false) || part == 'Model' }
47
+ end
48
+
49
+ memoize def model
50
+ self::MODELS_NAMESPACE.const_get(model_name, false)
51
+ end
52
+
53
+ memoize def instance_name
54
+ model_name.underscore.to_sym
55
+ end
56
+
57
+ memoize def instance_variable_name
58
+ :"@#{instance_name}"
59
+ end
60
+ end
61
+
62
+ def initialize(*)
63
+ @cached =
64
+ Sequel::Plugins.const_defined?(:StaticCache) &&
65
+ model.plugins.include?(Sequel::Plugins::StaticCache)
66
+
67
+ super
68
+ end
69
+
70
+ def before_retry
71
+ if instance_variable_defined?(instance_variable_name)
72
+ remove_instance_variable instance_variable_name
73
+ end
74
+
75
+ super
76
+ end
77
+
78
+ def instance
79
+ return @instance if defined?(@instance)
80
+
81
+ @instance = find_instance
82
+ end
83
+
84
+ private
85
+
86
+ def execute
87
+ # TODO: Check
88
+ Actions::Application::Restart.run if @cached && ENV['RACK_ENV'] != 'test'
89
+
90
+ instance
91
+ end
92
+
93
+ attr_writer :instance
94
+
95
+ def find_instance
96
+ model[id].public_send(@cached ? :dup : :itself)
97
+ end
98
+
99
+ def field_condition(name, value)
100
+ options = self.class.fields_and_nested_forms[name]
101
+
102
+ return instance_exec(name, value, &options[:condition]) if options.key?(:condition)
103
+
104
+ field_condition_class(options[:type]).new(name, value).result
105
+ end
106
+
107
+ using GorillaPatch::Inflections
108
+
109
+ def field_condition_class(type)
110
+ const_name = type.to_s.camelize
111
+ const_name = 'Base' if const_name.empty? || !Conditions.const_defined?(const_name, false)
112
+
113
+ Conditions.const_get(const_name, false)
114
+ end
115
+
116
+ def conditions_for_dataset(except: [])
117
+ conditions = fields_and_nested_forms.map do |name, value|
118
+ next Sequel[true] if Array(except).include?(name)
119
+
120
+ field_condition(name, value)
121
+ end
122
+
123
+ ## `[].reduce(:&)` returns `nil`
124
+ conditions.any? ? conditions.reduce(:&) : conditions
125
+ end
126
+
127
+ def compare_value(instance_value, value)
128
+ ## It can be Number, nil, etc., but logic for Regexp is below
129
+ instance_value = instance_value.to_s if value.is_a?(String) && !instance_value.is_a?(Regexp)
130
+
131
+ ## Match instead of equal if any side is Regexp
132
+ if instance_value.is_a?(Regexp) || value.is_a?(Regexp)
133
+ instance_value.match? value
134
+ ## And just equal if not
135
+ else
136
+ instance_value == value
137
+ end
138
+ end
139
+
140
+ def select_cached
141
+ model.all.select do |instance|
142
+ fields_and_nested_forms.all? do |key, values|
143
+ key =
144
+ self.class.fields_and_nested_forms[key].fetch(:compare_key, key)
145
+
146
+ Array(values).any? do |value|
147
+ compare_value instance.public_send(key), value
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ # Pluralizes instance_method name
154
+ module Plural
155
+ include Base
156
+ include Memery
157
+
158
+ using GorillaPatch::Inflections.from_sequel
159
+
160
+ memoize def instance_name
161
+ model_name.underscore.pluralize.to_sym
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formalism
4
+ module ModelForms
5
+ module Conditions
6
+ ## Base class for `:condition` form field option
7
+ class Base
8
+ def initialize(name, value)
9
+ @name = name
10
+ @value = value
11
+ end
12
+
13
+ def result
14
+ Sequel[@name => @value]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formalism
4
+ module ModelForms
5
+ ## Base form for model creation
6
+ module Create
7
+ def initialize(*)
8
+ super
9
+
10
+ @instance_from_initialization = @instance
11
+
12
+ initialize_instance
13
+ end
14
+
15
+ def before_retry
16
+ super
17
+
18
+ initialize_instance
19
+ end
20
+
21
+ private
22
+
23
+ def execute
24
+ instance.set(fields_and_nested_forms).save
25
+ super
26
+ end
27
+
28
+ def find_instance
29
+ nil
30
+ end
31
+
32
+ def initialize_instance
33
+ self.instance = model.new fields(for_merge: true)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formalism
4
+ module ModelForms
5
+ ## Base form for model deletion
6
+ module Delete
7
+ include Formalism::ModelForms::Base
8
+
9
+ # module ClassMethods
10
+ # def inherited(form)
11
+ # super
12
+ #
13
+ # return unless form.model.auditable?
14
+ #
15
+ # form.include RequiredChangesAuthor
16
+ # end
17
+ # end
18
+
19
+ field :id, Integer
20
+
21
+ private
22
+
23
+ def execute
24
+ instance.changes_author = changes_author if model.auditable?
25
+
26
+ instance.destroy
27
+ super
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formalism
4
+ module ModelForms
5
+ ## Base form for model finding
6
+ module Find
7
+ include Formalism::ModelForms::Base
8
+ include Memery
9
+
10
+ field :id, Integer, default: nil
11
+
12
+ def initialize(params_or_instance = {})
13
+ if params_or_instance.is_a?(Hash)
14
+ super(params_or_instance)
15
+ else
16
+ @initialized_with_instance = true
17
+ self.instance = params_or_instance
18
+ super()
19
+ end
20
+ end
21
+
22
+ def before_retry
23
+ return if @initialized_with_instance
24
+
25
+ super
26
+
27
+ return unless instance_variable_defined? :@instance
28
+
29
+ remove_instance_variable :@instance
30
+ end
31
+
32
+ private
33
+
34
+ def execute
35
+ self.instance = @cached ? find_cached : find_non_cached
36
+ end
37
+
38
+ def find_instance
39
+ return unless valid?
40
+
41
+ ## `run` can return `nil` if form is not `runnable`
42
+ run&.result
43
+ end
44
+
45
+ def find_cached
46
+ dataset.find do |instance|
47
+ fields_and_nested_forms.all? do |key, value|
48
+ compare_value instance[key], value
49
+ end
50
+ end
51
+ end
52
+
53
+ def find_non_cached
54
+ dataset.first
55
+ rescue Sequel::DatabaseError => e
56
+ ## I'm not sure that there is safe to use
57
+ ## `Sequel::DatabaseError`
58
+ raise e unless e.cause.is_a? PG::DataException
59
+ raise e if e.cause.is_a? PG::InvalidTextRepresentation
60
+ end
61
+
62
+ memoize def dataset
63
+ ## `Dataset#all` for `EAGER` with `.first` in Find forms
64
+ (@cached ? model : filtered_non_cached_dataset).all
65
+ end
66
+
67
+ memoize def filtered_non_cached_dataset
68
+ unfiltered_non_cached_dataset.where(conditions_for_dataset)
69
+ end
70
+
71
+ memoize def unfiltered_non_cached_dataset
72
+ (list_form_class&.new(params) || model).dataset
73
+ end
74
+
75
+ def list_form_class
76
+ return unless namespace.const_defined?(:List) && namespace::List.is_a?(Class)
77
+
78
+ namespace::List
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formalism
4
+ module ModelForms
5
+ ## Base form for model finding
6
+ module FindOrCreate
7
+ extend ::ModuleMethods::Extension
8
+
9
+ ## Module for class methods
10
+ module ClassMethods
11
+ def inherited(child_form)
12
+ super
13
+
14
+ child_form.nested :find, child_form.namespace::Find,
15
+ initialize: ->(form) { form.new(@params_or_instance) },
16
+ errors_key: nil
17
+
18
+ child_form.nested :create, child_form.namespace::Create,
19
+ initialize: ->(form) { form.new(@params_or_instance) },
20
+ errors_key: nil,
21
+ merge_errors: -> { find_form.instance.nil? }
22
+ end
23
+ end
24
+
25
+ def initialize(params_or_instance = {})
26
+ @params_or_instance = params_or_instance
27
+
28
+ super
29
+ end
30
+
31
+ def instance
32
+ find_form.instance || create_form.instance
33
+ end
34
+
35
+ private
36
+
37
+ def execute
38
+ self.instance = create_form.run.result unless instance.exists?
39
+ instance
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'flame/pagination/for_forms'
4
+
5
+ module Formalism
6
+ module ModelForms
7
+ ## Base form for model listing
8
+ module List
9
+ include Formalism::ModelForms::Base
10
+ include Memery
11
+ extend ModelForms::Base::Plural
12
+
13
+ ## Module for class methods
14
+ module ClassMethods
15
+ include Memery
16
+ using GorillaPatch::Namespace
17
+
18
+ memoize def namespace
19
+ return super if super.demodulize != 'List'
20
+
21
+ self::FORMS_NAMESPACE.const_get(super.deconstantize, false)
22
+ end
23
+
24
+ def search_fields(*fields)
25
+ @search_fields ||= Set.new
26
+ return @search_fields if fields.empty?
27
+
28
+ @search_fields.merge(fields)
29
+ end
30
+
31
+ def inherited(list_form)
32
+ super
33
+
34
+ list_form.search_fields(*search_fields)
35
+ end
36
+ end
37
+
38
+ EAGER = %i[].freeze
39
+
40
+ include Flame::Pagination::ForForms
41
+
42
+ field :search_query, merge: false
43
+
44
+ memoize def dataset
45
+ return select_cached if @cached
46
+
47
+ dataset =
48
+ ordered_unfiltered_dataset
49
+ .where(conditions_for_dataset)
50
+ .eager(*self.class::EAGER)
51
+
52
+ return dataset unless dataset.respond_to? :search
53
+
54
+ dataset.search(search_query, self.class.search_fields)
55
+ end
56
+
57
+ memoize def dataset_edges
58
+ [dataset.first, dataset.last]
59
+ end
60
+
61
+ private
62
+
63
+ def execute
64
+ self.instance =
65
+ if dataset
66
+ if @cached
67
+ then cached_dataset_for_execute
68
+ else non_cached_dataset_for_execute.all
69
+ end
70
+ else
71
+ []
72
+ end
73
+ end
74
+
75
+ def unfiltered_dataset
76
+ model.dataset
77
+ end
78
+
79
+ def ordered_unfiltered_dataset
80
+ result = unfiltered_dataset.from_self(alias: model.table_name)
81
+ result = result.reverse_order(:id) unless unfiltered_dataset.opts[:order]
82
+ result
83
+ end
84
+
85
+ def cached_dataset_for_execute
86
+ limit_by_page ? dataset[limit_by_page] : dataset
87
+ end
88
+
89
+ def non_cached_dataset_for_execute
90
+ dataset.where(id: dataset.select(:id).limit(limit_by_page))
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formalism
4
+ module ModelForms
5
+ ## Base form for model moving
6
+ module Move
7
+ include Formalism::ModelForms::Base
8
+
9
+ field :id, Integer
10
+
11
+ attr_reader :direction
12
+
13
+ def initialize(direction, id, how_many = 1)
14
+ @direction = direction.to_sym
15
+ @how_many = how_many.to_i
16
+
17
+ super(id: id)
18
+ end
19
+
20
+ private
21
+
22
+ POSSIBLE_DIRECTIONS = %i[up down].freeze
23
+
24
+ def validate
25
+ return if POSSIBLE_DIRECTIONS.include?(@direction)
26
+
27
+ errors.add :direction, :unknown, args: { direction: @direction }
28
+ end
29
+
30
+ def execute
31
+ instance.public_send(:"move_#{@direction}", @how_many)
32
+ super
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formalism
4
+ module ModelForms
5
+ ## Base form for many instances of model finding
6
+ module Select
7
+ include Formalism::ModelForms::Base
8
+ extend ModelForms::Base::Plural
9
+
10
+ field :id, Array, of: Integer, default: []
11
+
12
+ def initialize(params_or_instance = {})
13
+ ## Instance should be an `Array` if there is not `params`
14
+ params_or_instance = params_or_instance.to_a unless params_or_instance.is_a?(Hash)
15
+
16
+ super
17
+ end
18
+
19
+ private
20
+
21
+ def execute
22
+ self.instance = @cached ? select_cached : dataset
23
+ end
24
+
25
+ def instance_respond_to?(name)
26
+ @instance&.first&.respond_to?(name)
27
+ end
28
+
29
+ def instance_public_send(name)
30
+ @instance.map { |instance| instance.public_send(name) }
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formalism
4
+ module ModelForms
5
+ ## Base form for model updating
6
+ module Update
7
+ include Formalism::ModelForms::Base
8
+
9
+ ## Redefine `filed` and `nested` class methods with a specific `:default` from `instance`
10
+ module ClassMethods
11
+ %i[field nested].each do |method_name|
12
+ define_method(method_name) do |name, type_or_form = nil, **options|
13
+ unless method_name == :nested && options[:merge] == false
14
+ options[:default] = options.fetch(
15
+ :default, -> { instance&.public_send(name) }
16
+ )
17
+ end
18
+
19
+ super(name, type_or_form, **options)
20
+ end
21
+ end
22
+ end
23
+
24
+ field :id, Integer, merge: false
25
+
26
+ def initialize(params, id_or_instance)
27
+ if id_or_instance.is_a?(model)
28
+ self.instance = id_or_instance
29
+ else
30
+ self.id = id_or_instance
31
+ end
32
+
33
+ super params
34
+ end
35
+
36
+ private
37
+
38
+ def validate
39
+ return if instance
40
+
41
+ add_error :itself, :not_exist
42
+ end
43
+
44
+ def execute
45
+ instance.update(fields_and_nested_forms)
46
+ super
47
+ end
48
+
49
+ def field_changed?(field)
50
+ return true unless instance.respond_to?(field)
51
+
52
+ public_send(field) != instance.public_send(field)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formalism
4
+ module ModelForms
5
+ VERSION = '0.6.0'
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,288 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: formalism-model_forms
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Popov
8
+ - Ivan Tyurin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2020-09-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: alt_memery
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '2.0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '2.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: flame-pagination
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 0.3.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 0.3.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: formalism
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 0.2.0
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: 0.2.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: gorilla_patch
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '4.0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '4.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: module_methods
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: 0.1.0
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: 0.1.0
84
+ - !ruby/object:Gem::Dependency
85
+ name: sequel
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '5.0'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '5.0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: pry-byebug
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '3.9'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '3.9'
112
+ - !ruby/object:Gem::Dependency
113
+ name: bundler
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '2.0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '2.0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: gem_toys
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - "~>"
131
+ - !ruby/object:Gem::Version
132
+ version: 0.4.0
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: 0.4.0
140
+ - !ruby/object:Gem::Dependency
141
+ name: toys
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - "~>"
145
+ - !ruby/object:Gem::Version
146
+ version: 0.11.0
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - "~>"
152
+ - !ruby/object:Gem::Version
153
+ version: 0.11.0
154
+ - !ruby/object:Gem::Dependency
155
+ name: codecov
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: 0.2.0
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - "~>"
166
+ - !ruby/object:Gem::Version
167
+ version: 0.2.0
168
+ - !ruby/object:Gem::Dependency
169
+ name: rspec
170
+ requirement: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - "~>"
173
+ - !ruby/object:Gem::Version
174
+ version: '3.9'
175
+ type: :development
176
+ prerelease: false
177
+ version_requirements: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - "~>"
180
+ - !ruby/object:Gem::Version
181
+ version: '3.9'
182
+ - !ruby/object:Gem::Dependency
183
+ name: simplecov
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - "~>"
187
+ - !ruby/object:Gem::Version
188
+ version: 0.19.0
189
+ type: :development
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - "~>"
194
+ - !ruby/object:Gem::Version
195
+ version: 0.19.0
196
+ - !ruby/object:Gem::Dependency
197
+ name: rubocop
198
+ requirement: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - "~>"
201
+ - !ruby/object:Gem::Version
202
+ version: 0.91.0
203
+ type: :development
204
+ prerelease: false
205
+ version_requirements: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - "~>"
208
+ - !ruby/object:Gem::Version
209
+ version: 0.91.0
210
+ - !ruby/object:Gem::Dependency
211
+ name: rubocop-performance
212
+ requirement: !ruby/object:Gem::Requirement
213
+ requirements:
214
+ - - "~>"
215
+ - !ruby/object:Gem::Version
216
+ version: '1.0'
217
+ type: :development
218
+ prerelease: false
219
+ version_requirements: !ruby/object:Gem::Requirement
220
+ requirements:
221
+ - - "~>"
222
+ - !ruby/object:Gem::Version
223
+ version: '1.0'
224
+ - !ruby/object:Gem::Dependency
225
+ name: rubocop-rspec
226
+ requirement: !ruby/object:Gem::Requirement
227
+ requirements:
228
+ - - "~>"
229
+ - !ruby/object:Gem::Version
230
+ version: '1.0'
231
+ type: :development
232
+ prerelease: false
233
+ version_requirements: !ruby/object:Gem::Requirement
234
+ requirements:
235
+ - - "~>"
236
+ - !ruby/object:Gem::Version
237
+ version: '1.0'
238
+ description: 'Standard Formalism forms for Sequel Models, such like create, find,
239
+ delete, etc.
240
+
241
+ '
242
+ email: alex.wayfer@gmail.com
243
+ executables: []
244
+ extensions: []
245
+ extra_rdoc_files: []
246
+ files:
247
+ - CHANGELOG.md
248
+ - LICENSE.txt
249
+ - README.md
250
+ - lib/formalism/model_forms.rb
251
+ - lib/formalism/model_forms/_base.rb
252
+ - lib/formalism/model_forms/conditions/_base.rb
253
+ - lib/formalism/model_forms/create.rb
254
+ - lib/formalism/model_forms/delete.rb
255
+ - lib/formalism/model_forms/find.rb
256
+ - lib/formalism/model_forms/find_or_create.rb
257
+ - lib/formalism/model_forms/list.rb
258
+ - lib/formalism/model_forms/move.rb
259
+ - lib/formalism/model_forms/select.rb
260
+ - lib/formalism/model_forms/update.rb
261
+ - lib/formalism/model_forms/version.rb
262
+ homepage: https://github.com/AlexWayfer/formalism-model_forms
263
+ licenses:
264
+ - MIT
265
+ metadata:
266
+ source_code_uri: https://github.com/AlexWayfer/formalism-model_forms
267
+ homepage_uri: https://github.com/AlexWayfer/formalism-model_forms
268
+ changelog_uri: https://github.com/AlexWayfer/formalism-model_forms/blob/master/CHANGELOG.md
269
+ post_install_message:
270
+ rdoc_options: []
271
+ require_paths:
272
+ - lib
273
+ required_ruby_version: !ruby/object:Gem::Requirement
274
+ requirements:
275
+ - - ">="
276
+ - !ruby/object:Gem::Version
277
+ version: 2.5.0
278
+ required_rubygems_version: !ruby/object:Gem::Requirement
279
+ requirements:
280
+ - - ">="
281
+ - !ruby/object:Gem::Version
282
+ version: '0'
283
+ requirements: []
284
+ rubygems_version: 3.1.2
285
+ signing_key:
286
+ specification_version: 4
287
+ summary: Standard Formalism forms for Sequel Models
288
+ test_files: []