formalism-model_forms 0.6.0

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