input_attributes_from_validators 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ea33dbf007b19181f857847dc0cb7e9c9d505b84b8c421e6949f1f01c25e79b2
4
+ data.tar.gz: 390cd060a49ffb1e89c4ac164d1a8286ae786b2ae6e8a736f9fae6a57e4984d2
5
+ SHA512:
6
+ metadata.gz: bca3ae056bf69d856efd25590436b2ab4c04743bf55e00f86513d830c7f6c827f9d1aeb928ad33826fda693ae144c2a938432110ad3abcfb3d585cb3384e3a54
7
+ data.tar.gz: 1495b8ab30226d5ac3f614aae92448c59ddbd84b2dac9a1ea4c2983fa86b20aa8b5372a2a2670b2b2c7681ce6b91cf3ff0cab7eda10e1c1bfb265b7be19bcd5b
data/CHANGELOG.md ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,90 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ input_attributes_from_validators (0.0.1)
5
+ railties (>= 4)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ actionpack (7.0.3)
11
+ actionview (= 7.0.3)
12
+ activesupport (= 7.0.3)
13
+ rack (~> 2.0, >= 2.2.0)
14
+ rack-test (>= 0.6.3)
15
+ rails-dom-testing (~> 2.0)
16
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
17
+ actionview (7.0.3)
18
+ activesupport (= 7.0.3)
19
+ builder (~> 3.1)
20
+ erubi (~> 1.4)
21
+ rails-dom-testing (~> 2.0)
22
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
23
+ activesupport (7.0.3)
24
+ concurrent-ruby (~> 1.0, >= 1.0.2)
25
+ i18n (>= 1.6, < 2)
26
+ minitest (>= 5.1)
27
+ tzinfo (~> 2.0)
28
+ builder (3.2.4)
29
+ concurrent-ruby (1.1.10)
30
+ crass (1.0.6)
31
+ diff-lcs (1.5.0)
32
+ erubi (1.10.0)
33
+ i18n (1.10.0)
34
+ concurrent-ruby (~> 1.0)
35
+ loofah (2.18.0)
36
+ crass (~> 1.0.2)
37
+ nokogiri (>= 1.5.9)
38
+ method_source (1.0.0)
39
+ minitest (5.15.0)
40
+ nokogiri (1.13.6-arm64-darwin)
41
+ racc (~> 1.4)
42
+ racc (1.6.0)
43
+ rack (2.2.3.1)
44
+ rack-test (1.1.0)
45
+ rack (>= 1.0, < 3)
46
+ rails-dom-testing (2.0.3)
47
+ activesupport (>= 4.2.0)
48
+ nokogiri (>= 1.6)
49
+ rails-html-sanitizer (1.4.3)
50
+ loofah (~> 2.3)
51
+ railties (7.0.3)
52
+ actionpack (= 7.0.3)
53
+ activesupport (= 7.0.3)
54
+ method_source
55
+ rake (>= 12.2)
56
+ thor (~> 1.0)
57
+ zeitwerk (~> 2.5)
58
+ rake (13.0.6)
59
+ rspec (3.11.0)
60
+ rspec-core (~> 3.11.0)
61
+ rspec-expectations (~> 3.11.0)
62
+ rspec-mocks (~> 3.11.0)
63
+ rspec-core (3.11.0)
64
+ rspec-support (~> 3.11.0)
65
+ rspec-expectations (3.11.0)
66
+ diff-lcs (>= 1.2.0, < 2.0)
67
+ rspec-support (~> 3.11.0)
68
+ rspec-mocks (3.11.1)
69
+ diff-lcs (>= 1.2.0, < 2.0)
70
+ rspec-support (~> 3.11.0)
71
+ rspec-support (3.11.0)
72
+ thor (1.2.1)
73
+ tzinfo (2.0.4)
74
+ concurrent-ruby (~> 1.0)
75
+ webrick (1.7.0)
76
+ yard (0.9.28)
77
+ webrick (~> 1.7.0)
78
+ zeitwerk (2.5.4)
79
+
80
+ PLATFORMS
81
+ arm64-darwin-21
82
+
83
+ DEPENDENCIES
84
+ input_attributes_from_validators!
85
+ rake (~> 13)
86
+ rspec (~> 3)
87
+ yard (>= 0.9.20, < 1)
88
+
89
+ BUNDLED WITH
90
+ 2.3.15
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Sergey Pedan
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.
data/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # HTML input attributes helper
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/input_attributes_from_validators.svg)](https://badge.fury.io/rb/input_attributes_from_validators)
4
+
5
+ ## Installation
6
+
7
+ ```ruby
8
+ gem "input_attributes_from_validators"
9
+ ```
10
+
11
+ ## The main idea
12
+
13
+ HTML inputs have powerful controls over browser via attributes:
14
+
15
+ - validations ([`min`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/min), [`max`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/max), [`minlength`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/minlength), [`maxlength`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/maxlength), [`required`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/required)) and
16
+ - keyboards variations ([`inputmode`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode), [`step`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/step)).
17
+
18
+ Normally you write those HTML attributes manually or forget about them, but most of them can be inferred from model validations and the DB column name.
19
+
20
+ ## How to use
21
+
22
+ Provided that you have validators on your model:
23
+
24
+ ```ruby
25
+ class Review < ActiveRecord::Base
26
+
27
+ validates :comment, presence: true, length: { min: 3, max: 1_000 }
28
+ validates :score, numericality: { only_integer: true, in: 1..5 }
29
+ end
30
+ ```
31
+
32
+ ### Individual helper methods
33
+
34
+ This gem exposes a set of helper methods, one for the corresponding HTML attribute:
35
+
36
+ ```ruby
37
+ validated_inputmode @rating, :comment #=> "text"
38
+ validated_minlength @review, :comment #=> 3
39
+ validated_maxlength @review, :comment #=> 1_000
40
+ validated_required @review, :comment #=> true
41
+ ```
42
+
43
+ ```ruby
44
+ validated_inputmode @rating, :score #=> "numeric"
45
+ validated_min @rating, :score #=> 1
46
+ validated_max @rating, :score #=> 5
47
+ validated_step @rating, :score #=> 1
48
+ ```
49
+
50
+ ### Aggregate method
51
+
52
+ There is also a method that returns a hash with all the values:
53
+
54
+ ```ruby
55
+ resolved_input_attributes(record, attribute_name) #=>
56
+ {
57
+ inputmode: <String || NilClass>,,
58
+ max: <Integer || NilClass>,
59
+ maxlength: <Integer || NilClass>,
60
+ min: <Integer || NilClass>,
61
+ minlength: <Integer || NilClass>,
62
+ required: <Boolean>,
63
+ step: <Integer || Decimal>,
64
+ }
65
+ ```
66
+
67
+ so you don’t have to repeadedly pass the record and the attribute name:
68
+
69
+ ```ruby
70
+ = form_for model: @review do |f|
71
+ - attrs = resolved_input_attributes(@review, :score)
72
+
73
+ = f.number_field :size \
74
+ inputmode: attrs[:inputmode], \
75
+ max: attrs[:max], \
76
+ min: attrs[:min], \
77
+ required: attrs[:required], \
78
+ step: attrs[:step]
79
+
80
+ = f.text_field :description \
81
+ inputmode: attrs[:inputmode], \
82
+ maxlength: attrs[:maxlength], \
83
+ minlength: attrs[:minlength], \
84
+ required: attrs[:required]
85
+ ```
86
+
87
+ ## Less useful methods
88
+
89
+ Search for validators with certain conditions:
90
+
91
+ ```ruby
92
+ validators_for(record: @review, attr: :comment, type: :length, options: [:maximm])
93
+ #=> 255
94
+
95
+ validators_for(record: @review, attr: :score, type: :numericality, options: [:less_than, :less_than_or_equal_to])
96
+ #=> 5
97
+ ```
98
+
99
+ Also
100
+
101
+ ```ruby
102
+ validated_value(record: @review, attr: :comment, type: :length, options: [:maximm])
103
+ #=> 255
104
+ ```
105
+
106
+ ```ruby
107
+ validator_type_to_class :presence #=> ActiveRecord::Validations::PresenceValidator
108
+ validator_type_to_class :numericality #=> ActiveRecord::Validations::NumericalityValidator
109
+ ```
110
+
111
+ ## Todo
112
+
113
+ - [ ] pattern attribute
data/Rakefile ADDED
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+
3
+ require "bundler/setup"
4
+ require "bundler/gem_tasks"
5
+ require "rspec/core/rake_task"
6
+ # require "term/ansicolor"
7
+ require "yard"
8
+
9
+ require "./lib/input_attributes_from_validators"
10
+
11
+ Bundler::GemHelper.install_tasks
12
+ RSpec::Core::RakeTask.new(:spec)
13
+
14
+ desc "Generate documentation"
15
+ YARD::Rake::YardocTask.new(:yard) do |t|
16
+ end
17
+ task doc: :yard
18
+
19
+ # APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
20
+ # load "rails/tasks/engine.rake"
21
+ load "rails/tasks/statistics.rake"
22
+
23
+ task default: :spec
24
+
25
+ # desc "Publish"
26
+ # task :publish do
27
+ # puts `gem push pkg/input_attributes_from_validators-#{InputAttributesFromValidators::VERSION}.gem`
28
+ # end
29
+
30
+ # require 'rake/testtask'
31
+ # Rake::TestTask.new do |t|
32
+ # t.libs << 'test'
33
+ # t.test_files = FileList['test/**/*_test.rb']
34
+ # t.verbose = false
35
+ # t.warning = false
36
+ # end
37
+
38
+ # desc 'Test all Gemfiles from test/*.gemfile'
39
+ # task :test_all_gemfiles do
40
+ # require 'term/ansicolor'
41
+ # require 'pty'
42
+ # require 'shellwords'
43
+ # cmd = 'bundle install --quiet && bundle exec rake --trace'
44
+ # statuses = Dir.glob('./test/gemfiles/*{[!.lock]}').map do |gemfile|
45
+ # env = {'BUNDLE_GEMFILE' => gemfile}
46
+ # cmd_with_env = " (#{env.map { |k, v| "export #{k}=#{Shellwords.escape v}" } * ' '}; #{cmd})"
47
+ # $stderr.puts Term::ANSIColor.cyan("Testing\n#{cmd_with_env}")
48
+ # Bundler.with_clean_env do
49
+ # PTY.spawn(env, cmd) do |r, _w, pid|
50
+ # begin
51
+ # r.each_line { |l| puts l }
52
+ # rescue Errno::EIO
53
+ # # Errno:EIO error means that the process has finished giving output.
54
+ # ensure
55
+ # ::Process.wait pid
56
+ # end
57
+ # end
58
+ # end
59
+ # [$? && $?.exitstatus == 0, cmd_with_env]
60
+ # end
61
+ # failed_cmds = statuses.reject(&:first).map { |(_status, cmd_with_env)| cmd_with_env }
62
+ # if failed_cmds.empty?
63
+ # $stderr.puts Term::ANSIColor.green('Tests pass with all gemfiles')
64
+ # else
65
+ # $stderr.puts Term::ANSIColor.red("Failing (#{failed_cmds.size} / #{statuses.size})\n#{failed_cmds * "\n"}")
66
+ # exit 1
67
+ # end
68
+ # end
69
+
70
+ # desc 'Start a dummy Rails app server'
71
+ # task :rails_server do
72
+ # require 'rack'
73
+ # require 'term/ansicolor'
74
+ # port = ENV['PORT'] || 9292
75
+ # puts %Q(Starting on #{Term::ANSIColor.cyan "http://localhost:#{port}"})
76
+ # Rack::Server.start(
77
+ # config: 'test/dummy_rails/config.ru',
78
+ # Port: port)
79
+ # end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AttributesHelper
4
+
5
+ # @param [ActiveRecord::Base] record
6
+ # @param [String, Symbol] attr
7
+ # @return [Hash]
8
+ #
9
+ def resolved_input_attributes(record, attr)
10
+ {
11
+ inputmode: validated_inputmode(record, attr),
12
+ max: validated_max(record, attr),
13
+ maxlength: validated_maxlength(record, attr),
14
+ min: validated_min(record, attr),
15
+ minlength: validated_minlength(record, attr),
16
+ required: validated_required(record, attr),
17
+ }.compact
18
+ end
19
+
20
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InputModeHelper
4
+
5
+ # @param [ActiveRecord::Base] record
6
+ # @param [String, Symbol] attr
7
+ # @return [String, NilClass]
8
+ # @example
9
+ # validated_inputmode @user, :email #=> "email"
10
+ # validated_inputmode @rating, :comment #=> "text"
11
+ # validated_inputmode @rating, :score #=> "numeric"
12
+ #
13
+ def validated_inputmode(record, attr)
14
+ v_types = validators_for_attr(record, attr).map(&:kind)
15
+
16
+ # TODO: try using pattern matching instead
17
+ if v_types.include?("numericality")
18
+ needs_integer?(record, attr) ? "numeric" : "decimal"
19
+ elsif v_types.include?("email")
20
+ "email"
21
+ elsif v_types.include?("url")
22
+ "url"
23
+ elsif ["tel", "phone"].any? { |i| v_types.include?(i) }
24
+ "tel"
25
+ elsif ["search"].any? { |i| v_types.include?(i) } || attr.to_s.include?("search")
26
+ "search"
27
+ else
28
+ "text"
29
+ end
30
+ end
31
+
32
+ # @param [ActiveRecord::Base] record
33
+ # @param [String, Symbol] attr
34
+ # @return [Numeric, NilClass]
35
+ # @example
36
+ # validated_step @rating, :score #=> 1
37
+ # validated_step @dumbbell, :weight #=> 0.25
38
+ #
39
+ def validated_step(record, attr)
40
+ case validated_inputmode(record, attr)
41
+ when "numeric" then 1
42
+ when "decimal" then 0.1
43
+ end
44
+ end
45
+
46
+
47
+ # https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/pattern
48
+ # def validated_pattern(record, attr)
49
+ # end
50
+
51
+ private def needs_integer?(record, attr)
52
+ validated_value(record: record, attr: attr, type: :numericality, options: [:only_integer])
53
+ end
54
+
55
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InputTypeHelper
4
+
5
+ # @param [ActiveRecord::Base] record
6
+ # @param [String, Symbol] attr
7
+ # @return [String, NilClass]
8
+ # @example
9
+ # resolved_input_type @user, :email #=> "email"
10
+ # resolved_input_type @rating, :comment #=> "text"
11
+ # resolved_input_type @rating, :score #=> "numeric"
12
+ #
13
+ def resolved_input_type(record, attr)
14
+ v_types = validators_for_attr(record, attr).map(&:kind)
15
+ klass = record.class
16
+
17
+ # TODO: try using pattern matching instead
18
+ if v_types.include? "numericality" or [:integer, :bigint, :float, :decimal].include? klass.column_for_attribute(attr).type
19
+ "number"
20
+
21
+ elsif v_types.include? "email" or attr.to_s.include? "email"
22
+ "email"
23
+
24
+ elsif v_types.include? "url" or attr.to_s.include? "url"
25
+ "url"
26
+
27
+ elsif v_types.include? "tel" or attr.to_s.include? "tel"
28
+ "tel"
29
+
30
+ elsif v_types.include? "phone" or attr.to_s.include? "phone"
31
+ "tel"
32
+
33
+ elsif v_types.include? "color" or attr.to_s.include? "color"
34
+ "color"
35
+
36
+ elsif ["search"].any? { |i| v_types.include?(i) } or attr.to_s.include? "search"
37
+ "search"
38
+
39
+ elsif klass.column_for_attribute(attr).type == :text
40
+ validated_value(record: record, attr: attr, type: :length, options: [:maximm]).to_i > 256 ? "textarea" : "text"
41
+
42
+ elsif klass.column_for_attribute(attr).type == :date
43
+ "date"
44
+
45
+ elsif klass.column_for_attribute(attr).type == :datetime
46
+ "datetimelocal"
47
+
48
+ elsif klass.column_for_attribute(attr).type == :time
49
+ "time"
50
+
51
+ else
52
+ "text"
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LimitsHelper
4
+
5
+ # @example
6
+ # validated_maxlength @review, :comment #=> 1_000
7
+ # @param [ActiveRecord::Base] record
8
+ # @param [String, Symbol] attr
9
+ # @return [Integer, NilClass]
10
+ # @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/maxlength
11
+ # @raise [TypeError]
12
+ #
13
+ def validated_maxlength(record, attr)
14
+ maximum = validated_value(record: record, attr: attr, type: :length, options: [:maximum])
15
+ range = validated_value(record: record, attr: attr, type: :length, options: [:in])
16
+ range&.max || maximum
17
+ end
18
+
19
+ # @example
20
+ # validated_minlength @review, :comment #=> 3
21
+ # @param [ActiveRecord::Base] record
22
+ # @param [String, Symbol] attr
23
+ # @return [Integer, NilClass]
24
+ # @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/minlength
25
+ # @raise [TypeError]
26
+ #
27
+ def validated_minlength(record, attr)
28
+ minimum = validated_value(record: record, attr: attr, type: :length, options: [:minimum])
29
+ range = validated_value(record: record, attr: attr, type: :length, options: [:in])
30
+ range&.min || minimum
31
+ end
32
+
33
+ # @example
34
+ # validated_required @rating, :score #=> 5
35
+ # @param [ActiveRecord::Base] record
36
+ # @param [String, Symbol] attr
37
+ # @return [Integer, NilClass]
38
+ # @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/max
39
+ # @raise [TypeError]
40
+ #
41
+ def validated_max(record, attr)
42
+ validated_value(record: record, attr: attr, type: :numericality, options: [:less_than, :less_than_or_equal_to])
43
+ end
44
+
45
+ # @example
46
+ # validated_min @rating, :score #=> 1
47
+ # @param [ActiveRecord::Base] record
48
+ # @param [String, Symbol] attr
49
+ # @return [Integer, NilClass]
50
+ # @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/min
51
+ # @raise [TypeError]
52
+ #
53
+ def validated_min(record, attr)
54
+ validated_value(record: record, attr: attr, type: :numericality, options: [:greater_than, :greater_than_or_equal_to])
55
+ end
56
+
57
+ # @example
58
+ # validated_required @user, :email #=> true
59
+ # @param [ActiveRecord::Base] record
60
+ # @param [String, Symbol] attr
61
+ # @return [Boolean]
62
+ # @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/required
63
+ # @raise [TypeError]
64
+ #
65
+ def validated_required(record, attr)
66
+ # validated_value(record: record, attr: attr, type: :presence, options: [:presece]) ?
67
+ validators_for(record: record, attr: attr, type: :presence).any?
68
+ end
69
+
70
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ValidatorsReflectionHelper
4
+
5
+ # @example
6
+ # validators_for_attr(User.new, :email) #=>
7
+ # [
8
+ # <ActiveRecord::Validations::PresenceValidator:0x @attributes=[:email], @options={}>,
9
+ # <EmailValidator:0x @attributes=[:email], @options={}>,
10
+ # <ActiveRecord::Validations::UniquenessValidator:0x @attributes=[:email], @options={}>,
11
+ # <ActiveRecord::Validations::PresenceValidator:0x @attributes=[:email], @options={:if=>:email_required?}>,
12
+ # <ActiveRecord::Validations::UniquenessValidator:0x @attributes=[:email], @options={:allow_blank=>true, :case_sensitive=>true, :if=>:will_save_change_to_email?}>,
13
+ # <ActiveModel::Validations::FormatValidator:0x @attributes=[:email], @options= {:allow_blank=>true, :if=>:will_save_change_to_email?}>
14
+ # ]
15
+ # @param [ActiveRecord::Base] record
16
+ # @param [String, Symbol] attr
17
+ # @raise [TypeError]
18
+ #
19
+ def validators_for_attr(record, attr)
20
+ fail TypeError, "`attr` must be a Symbol or String, you pass a #{attr.class}" unless [Symbol, String].include? attr.class
21
+ # TODO: fail TypeError if record.class.ancestors.include?()
22
+
23
+ record.class.validators.select { _1.attributes.include? attr }
24
+ end
25
+
26
+ # @param [ActiveRecord::Base] record
27
+ # @param [String, Symbol] attr
28
+ # @param [Array<Symbol>] options
29
+ # @raise [TypeError]
30
+ #
31
+ def validators_for(record:, attr:, type: nil, options: [])
32
+ fail TypeError, "`options` must be an Array, you pass a #{options.class}" unless options.is_a? Array
33
+ result = validators_for_attr(record, attr).select { _1.options.keys & options }
34
+ result = result.select { _1.is_a? validator_type_to_class(type) } if type.present?
35
+ result
36
+ end
37
+
38
+ # @example
39
+ # validated_value(record: @review, attr: :comment, type: :length, options: [:maximm]) #=> 255
40
+ # @param [ActiveRecord::Base] record
41
+ # @param [String, Symbol] attr
42
+ # @return [Integer, NilClass, Boolean]
43
+ # @raise [TypeError]
44
+ # @raise [TypeError]
45
+ #
46
+ def validated_value(record:, attr:, type: nil, options: [])
47
+ fail TypeError, "`options` must be an Array, you pass a #{options.class}" unless options.is_a? Array
48
+ validators_for(record: record, attr: attr, type: type, options: options).map { first_value(_1, options) }.compact.first
49
+ end
50
+
51
+ # @param [String, Symbol, NilClass] type
52
+ # @example
53
+ # validator_type_to_class(:presence) #=> ActiveRecord::Validations::PresenceValidator
54
+ # validator_type_to_class(:numericality) #=> ActiveRecord::Validations::NumericalityValidator
55
+ #
56
+ def validator_type_to_class(type)
57
+ fail TypeError, "`type` must be a Symbol or String, you pass a #{type.class}" unless [Symbol, String, NilClass].include? type.class
58
+ ["ActiveRecord::Validations::", type.to_s.capitalize, "Validator"].join.constantize if type.present?
59
+ end
60
+
61
+ private def first_value(validator, options)
62
+ options.map { |key| validator.options&.fetch(key, nil) }.compact.first
63
+ end
64
+
65
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/input_attributes_from_validators/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "input_attributes_from_validators"
7
+ spec.version = InputAttributesFromValidators::VERSION
8
+ spec.authors = ["Sergey Pedan"]
9
+ spec.email = ["sergey.pedan@gmail.com"]
10
+ spec.license = "MIT"
11
+
12
+ spec.summary = "A collection of helper methods for Rails to automate assigning HTML input attributes like maxlength, required, inputmode etc."
13
+ spec.description = <<~HEREDOC
14
+ #{spec.summary}.
15
+ HEREDOC
16
+
17
+ spec.homepage = "https://github.com/sergeypedan/#{spec.name.gsub('_', '-')}"
18
+ spec.extra_rdoc_files = ["README.md", "CHANGELOG.md"]
19
+ spec.rdoc_options = ["--charset=UTF-8"]
20
+ spec.metadata = { "changelog_uri" => "#{spec.homepage}/blob/master/CHANGELOG.md",
21
+ "documentation_uri" => "https://www.rubydoc.info/gems/#{spec.name}",
22
+ "homepage_uri" => "https://sergeypedan.ru/open_source_projects/#{spec.name.gsub('_', '-')}",
23
+ "source_code_uri" => spec.homepage }
24
+
25
+ spec.require_paths = ["app", "lib"]
26
+
27
+ spec.bindir = "exe"
28
+ spec.executables = []
29
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
30
+ `git ls-files`.split("\n")
31
+ .reject { |f| %w[bin spec test].any? { |dir| f.start_with? dir } }
32
+ .reject { |f| f.start_with? "." }
33
+ end
34
+
35
+ spec.add_runtime_dependency "railties", ">= 4"
36
+
37
+ spec.add_development_dependency "rake", "~> 13"
38
+ spec.add_development_dependency "rspec", "~> 3"
39
+ spec.add_development_dependency "yard", ">= 0.9.20", "< 1"
40
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InputAttributesFromValidators
4
+
5
+ # This is standard Rails way to autoload gem’s contents dynamically as an “engine”
6
+ # @see https://guides.rubyonrails.org/engines.html Rails guide on engines
7
+ #
8
+ class Engine < ::Rails::Engine
9
+ end
10
+
11
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InputAttributesFromValidators
4
+ VERSION = "0.0.1"
5
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require_relative "input_attributes_from_validators/version"
6
+ require_relative "input_attributes_from_validators/engine"
7
+
8
+ require_relative "../app/helpers/attributes_helper"
9
+ require_relative "../app/helpers/input_mode_helper"
10
+ require_relative "../app/helpers/input_type_helper"
11
+ require_relative "../app/helpers/limits_helper"
12
+ require_relative "../app/helpers/validators_reflection_helper"
13
+
14
+
15
+ module InputAttributesFromValidators
16
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: input_attributes_from_validators
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sergey Pedan
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-06-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.20
62
+ - - "<"
63
+ - !ruby/object:Gem::Version
64
+ version: '1'
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: 0.9.20
72
+ - - "<"
73
+ - !ruby/object:Gem::Version
74
+ version: '1'
75
+ description: 'A collection of helper methods for Rails to automate assigning HTML
76
+ input attributes like maxlength, required, inputmode etc..
77
+
78
+ '
79
+ email:
80
+ - sergey.pedan@gmail.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files:
84
+ - README.md
85
+ - CHANGELOG.md
86
+ files:
87
+ - CHANGELOG.md
88
+ - Gemfile
89
+ - Gemfile.lock
90
+ - LICENSE.txt
91
+ - README.md
92
+ - Rakefile
93
+ - app/helpers/attributes_helper.rb
94
+ - app/helpers/input_mode_helper.rb
95
+ - app/helpers/input_type_helper.rb
96
+ - app/helpers/limits_helper.rb
97
+ - app/helpers/validators_reflection_helper.rb
98
+ - input_attributes_from_validators.gemspec
99
+ - lib/input_attributes_from_validators.rb
100
+ - lib/input_attributes_from_validators/engine.rb
101
+ - lib/input_attributes_from_validators/version.rb
102
+ homepage: https://github.com/sergeypedan/input-attributes-from-validators
103
+ licenses:
104
+ - MIT
105
+ metadata:
106
+ changelog_uri: https://github.com/sergeypedan/input-attributes-from-validators/blob/master/CHANGELOG.md
107
+ documentation_uri: https://www.rubydoc.info/gems/input_attributes_from_validators
108
+ homepage_uri: https://sergeypedan.ru/open_source_projects/input-attributes-from-validators
109
+ source_code_uri: https://github.com/sergeypedan/input-attributes-from-validators
110
+ post_install_message:
111
+ rdoc_options:
112
+ - "--charset=UTF-8"
113
+ require_paths:
114
+ - app
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubygems_version: 3.0.3.1
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: A collection of helper methods for Rails to automate assigning HTML input
131
+ attributes like maxlength, required, inputmode etc.
132
+ test_files: []