active_dry_form 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,129 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveDryForm
4
- class Form
4
+ class Form < BaseForm
5
5
 
6
6
  include Dry::Monads[:result]
7
- Dry::Schema.load_extensions(:info)
7
+ Dry::Schema.load_extensions(:json_schema)
8
8
  ResultError = Class.new(StandardError)
9
9
 
10
- class ContractBase < Dry::Validation::Contract
10
+ cattr_accessor :contract_klass, instance_accessor: false, default: ::ActiveDryForm::BaseContract
11
11
 
12
- config.messages.load_paths << 'config/locales/dry_validation.ru.yml'
13
- config.messages.default_locale = :ru
12
+ def self.fields(namespace, i18n_key: nil, &block)
13
+ const_set :CURRENT_CONTRACT, Class.new(contract_klass, &block).new
14
+ const_set :FIELDS_INFO, self::CURRENT_CONTRACT.schema.json_schema(loose: true)
14
15
 
15
- end
16
-
17
- def self.fields(namespace, &block)
18
- const_set :NAMESPACE, ActiveModel::Name.new(nil, nil, namespace.to_s)
19
- const_set :CURRENT_CONTRACT, Class.new(ContractBase, &block).new
20
- const_set :FIELDS_INFO, self::CURRENT_CONTRACT.schema.info[:keys]
21
-
22
- self::FIELDS_INFO.each do |key, value|
23
- if value[:keys]
24
- sub_klass = Class.new do
25
- const_set :NAMESPACE, ActiveModel::Name.new(nil, nil, key.to_s)
26
- const_set :FIELDS_INFO, value[:keys]
27
-
28
- def initialize(params, record, errors)
29
- @params = params || {}
30
- @record = record
31
- @errors = errors || {}
32
- end
33
-
34
- self::FIELDS_INFO.each_key do |sub_key|
35
- define_method sub_key do
36
- @params[sub_key] || @record.try(sub_key)
37
- end
38
-
39
- def model_name
40
- self.class::NAMESPACE
41
- end
42
-
43
- def info(sub_key)
44
- self.class::FIELDS_INFO[sub_key]
45
- end
16
+ const_set :NAMESPACE, ActiveModel::Name.new(nil, nil, namespace.name.capitalize)
17
+ const_get(:NAMESPACE).i18n_key = i18n_key if i18n_key
46
18
 
47
- # ActionView::Helpers::Tags::Translator#human_attribute_name
48
- def to_model
49
- self
50
- end
51
-
52
- def self.human_attribute_name(field)
53
- I18n.t(field, scope: :"activerecord.attributes.#{self::NAMESPACE.i18n_key}")
54
- end
55
-
56
- def errors
57
- @errors
58
- end
59
- end
60
- end
61
- define_method key do
62
- sub_klass.new(@params[key], @record.try(key), errors[key])
63
- end
64
- else
65
- define_method key do
66
- @params[key] || @record.try(key)
67
- end
68
- end
69
- end
70
- end
71
-
72
- def self.default(method)
73
- alias_method :"__#{method}", method
74
-
75
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
76
- # def create_default(...)
77
- # @params.merge!(__create_default(...))
78
- # end
79
-
80
- def #{method}(...)
81
- @params.merge!(__#{method}(...))
82
- end
83
- RUBY
19
+ define_methods
84
20
  end
85
21
 
86
22
  def self.action(method)
87
23
  alias_method :"__#{method}", method
88
24
 
89
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
90
- # def create(...)
91
- # if validator.failure?
92
- # @base_errors = validator.errors.filter(:base?).map(&:to_s).presence
93
- # return Failure(:validate_invalid)
94
- # end
95
- #
96
- # result = __create(...)
97
- #
98
- # unless result.is_a?(::Dry::Monads::Result)
99
- # raise ResultError, 'method `create` should be returning `monad`'
100
- # end
101
- #
102
- # case result
103
- # in Failure[:failure_service, base_errors]
104
- # @base_errors = base_errors
105
- # else
106
- # end
107
- #
108
- # result
109
- # end
110
-
25
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Style/DocumentDynamicEvalDefinition
111
26
  def #{method}(...)
112
- if validator.failure?
113
- @base_errors = validator.errors.filter(:base?).map(&:to_s).presence
114
- return Failure(:validate_invalid)
115
- end
27
+ validate
28
+ return Failure(:invalid_form) unless valid?
116
29
 
117
30
  result = __#{method}(...)
118
31
 
119
- unless result.is_a?(::Dry::Monads::Result)
120
- raise ResultError, 'method `#{method}` should be returning `monad`'
121
- end
122
-
123
32
  case result
124
- in Failure[:failure_service, base_errors]
125
- @base_errors = base_errors
33
+ when ::Dry::Monads::Result::Failure
34
+ @base_errors = Array.wrap(result.failure)
35
+ when ::Dry::Monads::Result::Success
126
36
  else
37
+ raise ResultError, 'method `#{method}` must return `monad`'
127
38
  end
128
39
 
129
40
  result
@@ -131,81 +42,5 @@ module ActiveDryForm
131
42
  RUBY
132
43
  end
133
44
 
134
- attr_reader :base_errors, :record
135
-
136
- def initialize(record: nil, params_form: nil, params_init: nil)
137
- raise 'in `params_form` use `request.parameters` instead of `params`' if params_form.is_a?(::ActionController::Parameters)
138
- raise 'in `params_init` use `request.parameters` instead of `params`' if params_init.is_a?(::ActionController::Parameters)
139
-
140
- @params =
141
- if params_form
142
- _deep_transform_values_in_params!(params_form[self.class::NAMESPACE.param_key].deep_transform_keys!(&:to_sym))
143
- elsif params_init
144
- params_init.deep_transform_keys!(&:to_sym)
145
- else
146
- {}
147
- end
148
-
149
- @record = record if record
150
- end
151
-
152
- def info(key)
153
- self.class::FIELDS_INFO[key]
154
- end
155
-
156
- def model_name
157
- self.class::NAMESPACE
158
- end
159
-
160
- # ActionView::Helpers::Tags::Translator#human_attribute_name
161
- def to_model
162
- self
163
- end
164
-
165
- def self.human_attribute_name(field)
166
- I18n.t(field, scope: :"activerecord.attributes.#{self::NAMESPACE.i18n_key}")
167
- end
168
-
169
- def persisted?
170
- @record&.persisted?
171
- end
172
-
173
- def to_key
174
- key = @record&.id
175
- [key] if key
176
- end
177
-
178
- # используется при генерации URL, когда record.persisted?
179
- def to_param
180
- @record.id.to_s
181
- end
182
-
183
- def validator
184
- @validator ||= self.class::CURRENT_CONTRACT.call(@params, { form: self })
185
- end
186
-
187
- def errors
188
- @errors ||= @validator ? @validator.errors.to_h : {}
189
- end
190
-
191
- def view_component
192
- self.class.module_parent::Component.new(self)
193
- end
194
-
195
- private def _deep_transform_values_in_params!(object)
196
- case object
197
- when String
198
- object.strip.presence
199
- when Hash
200
- object.transform_values! { |value| _deep_transform_values_in_params!(value) }
201
- when Array
202
- object.map! { |e| _deep_transform_values_in_params!(e) }
203
- object.compact!
204
- object
205
- else
206
- object
207
- end
208
- end
209
-
210
45
  end
211
46
  end
@@ -3,14 +3,23 @@
3
3
  module ActiveDryForm
4
4
  module FormHelper
5
5
 
6
- def active_dry_form_for(name, options = {})
6
+ def active_dry_form_for(name, options = {}, &block)
7
7
  options[:builder] = ActiveDryForm::Builder
8
- options[:html] ||= {}
9
- options[:html][:class] = "active-dry-form #{options[:html][:class]}"
8
+ options[:html] = html_options(options)
10
9
 
11
- form_for(name, options) do |f|
10
+ # Array.wrap because Hash === name, it breaks polymorphic_path
11
+ # TODO: refactor to options[:url]
12
+ form_for(Array.wrap(name), options) do |f|
12
13
  concat f.show_base_errors
13
- yield(f)
14
+ instance_exec(f, &block)
15
+ end
16
+ end
17
+
18
+ private def html_options(options)
19
+ classes = { class: ActiveDryForm.config.css_classes.form }
20
+
21
+ (options[:html] || {}).merge(ActiveDryForm.config.html_options.form, classes) do |_key, oldval, newval|
22
+ Array.wrap(newval) + Array.wrap(oldval)
14
23
  end
15
24
  end
16
25
 
@@ -3,32 +3,24 @@
3
3
  module ActiveDryForm
4
4
  class Input
5
5
 
6
- attr_reader :input_opts, :input_type
7
-
8
- def initialize(builder, method_type, method, options)
6
+ def initialize(builder, builder_method, field, options)
9
7
  @builder = builder
10
- @method_type = method_type
11
- @method = method
12
-
13
- info = builder.object.info(method)
14
- @input_type = info[:type]
15
- @required = info[:required]
8
+ @builder_method = builder_method
9
+ @field = field
16
10
 
17
11
  @label_opts = options[:label]
18
12
  @label_text = options[:label_text]
19
13
  @hint_text = options[:hint]
20
- @input_opts = options.except(:label, :hint, :label_text)
21
- @input_opts[:required] = true if @required
14
+ @required = options[:required]
15
+ @input_user_options = options.except(:label, :hint, :label_text)
22
16
  end
23
17
 
24
18
  def css_classes
25
19
  [
26
- 'input',
27
- @method_type,
28
- @input_type,
29
- @method,
30
- ('required' if @required),
31
- ('error' if error?(@method)),
20
+ ActiveDryForm.config.css_classes.input,
21
+ @builder_method,
22
+ (ActiveDryForm.config.css_classes.input_required if @required),
23
+ (ActiveDryForm.config.css_classes.input_error if error?(@field)),
32
24
  ].compact
33
25
  end
34
26
 
@@ -44,29 +36,29 @@ module ActiveDryForm
44
36
  end
45
37
 
46
38
  def label
47
- @builder.label(@method, @label_text) unless @label_opts == false
39
+ @builder.label(@field, @label_text) unless @label_opts == false
48
40
  end
49
41
 
50
42
  def hint_text
51
43
  return unless @hint_text
52
44
 
53
- @builder.tag.small @hint_text, class: 'help-text'
45
+ @builder.tag.small @hint_text, class: ActiveDryForm.config.css_classes.hint
54
46
  end
55
47
 
56
48
  def error_text
57
- return unless error?(@method)
49
+ return unless error?(@field)
58
50
 
59
51
  obj_error_text =
60
- case e = @builder.object.errors[@method]
52
+ case e = @builder.object.errors[@field]
61
53
  when Hash then e.values
62
54
  else e
63
55
  end
64
56
 
65
- @builder.tag.div obj_error_text.join('<br />'), class: 'form-error is-visible'
57
+ @builder.tag.div obj_error_text.join('<br />').html_safe, class: ActiveDryForm.config.css_classes.error
66
58
  end
67
59
 
68
- def error?(method)
69
- @builder.object.errors.key?(method)
60
+ def error?(field)
61
+ @builder.object.errors.key?(field)
70
62
  end
71
63
 
72
64
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveDryForm
4
- VERSION = "0.1.0"
4
+
5
+ VERSION = '1.0.0'
6
+
5
7
  end
@@ -1,13 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "active_dry_form/version"
4
- require_relative "active_dry_form/schema_compiler_patch"
5
- require_relative "active_dry_form/builder"
6
- require_relative "active_dry_form/form"
7
- require_relative "active_dry_form/input"
8
- require_relative "active_dry_form/form_helper"
3
+ require 'dry-monads'
4
+ require 'dry-validation'
5
+ require 'active_model'
6
+ require 'action_view'
7
+ require 'action_controller'
8
+
9
+ require_relative 'active_dry_form/version'
10
+ require_relative 'active_dry_form/configuration'
11
+ require_relative 'active_dry_form/builder'
12
+ require_relative 'active_dry_form/base_form'
13
+ require_relative 'active_dry_form/base_contract'
14
+ require_relative 'active_dry_form/form'
15
+ require_relative 'active_dry_form/input'
16
+ require_relative 'active_dry_form/form_helper'
9
17
 
10
18
  module ActiveDryForm
19
+
11
20
  class Error < StandardError; end
12
- # Your code goes here...
21
+ class ParamsNotAllowedError < Error; end
22
+ class DateTimeNotAllowedError < Error; end
23
+
13
24
  end
metadata CHANGED
@@ -1,17 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_dry_form
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ermolaev Andrey
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-20 00:00:00.000000000 Z
11
+ date: 2024-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: dry-validation
14
+ name: actionpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-configurable
15
43
  requirement: !ruby/object:Gem::Requirement
16
44
  requirements:
17
45
  - - ">="
@@ -38,6 +66,20 @@ dependencies:
38
66
  - - ">="
39
67
  - !ruby/object:Gem::Version
40
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: dry-validation
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
41
83
  description: Form validation for Rails with Dry-Validation
42
84
  email:
43
85
  - andruhafirst@yandex.ru
@@ -48,27 +90,30 @@ files:
48
90
  - ".editorconfig"
49
91
  - ".rspec"
50
92
  - ".rubocop.yml"
93
+ - ".tool-versions"
51
94
  - Gemfile
95
+ - Gemfile.lock
52
96
  - LICENSE.txt
53
97
  - README.md
54
98
  - Rakefile
55
99
  - bin/console
56
100
  - bin/setup
101
+ - config/locales/dry_validation.ru.yml
57
102
  - lib/active_dry_form.rb
103
+ - lib/active_dry_form/base_contract.rb
104
+ - lib/active_dry_form/base_form.rb
58
105
  - lib/active_dry_form/builder.rb
106
+ - lib/active_dry_form/configuration.rb
59
107
  - lib/active_dry_form/form.rb
60
108
  - lib/active_dry_form/form_helper.rb
61
109
  - lib/active_dry_form/input.rb
62
- - lib/active_dry_form/schema_compiler_patch.rb
63
110
  - lib/active_dry_form/version.rb
64
111
  homepage: https://github.com/corp-gp/active_dry_form
65
112
  licenses:
66
113
  - MIT
67
114
  metadata:
68
- allowed_push_host: https://rubygems.org
69
- homepage_uri: https://github.com/corp-gp/active_dry_form
70
- source_code_uri: https://github.com/corp-gp/active_dry_form
71
- post_install_message:
115
+ rubygems_mfa_required: 'true'
116
+ post_install_message:
72
117
  rdoc_options: []
73
118
  require_paths:
74
119
  - lib
@@ -76,15 +121,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
121
  requirements:
77
122
  - - ">="
78
123
  - !ruby/object:Gem::Version
79
- version: 2.6.0
124
+ version: 2.7.0
80
125
  required_rubygems_version: !ruby/object:Gem::Requirement
81
126
  requirements:
82
127
  - - ">="
83
128
  - !ruby/object:Gem::Version
84
129
  version: '0'
85
130
  requirements: []
86
- rubygems_version: 3.1.6
87
- signing_key:
131
+ rubygems_version: 3.3.17
132
+ signing_key:
88
133
  specification_version: 4
89
134
  summary: Form validation for Rails with Dry-Validation
90
135
  test_files: []
@@ -1,31 +0,0 @@
1
- require "dry/schema/extensions/info/schema_compiler"
2
-
3
- require "dry/schema/constants"
4
-
5
- module Dry
6
- module Schema
7
- module Info
8
- class SchemaCompiler
9
- def visit_not(_node, opts = {})
10
- key = opts[:key]
11
- keys[key][:nullable] = true
12
- end
13
-
14
- def visit_predicate(node, opts = {})
15
- name, rest = node
16
-
17
- key = opts[:key]
18
-
19
- if name.equal?(:key?)
20
- keys[rest[0][1]] = { required: opts.fetch(:required, true) }
21
- elsif name.equal?(:array?)
22
- keys[key][:array] = true
23
- else
24
- type = PREDICATE_TO_TYPE[name]
25
- keys[key][:type] = type if type
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end