eac_rails_utils 0.10.1 → 0.11.4

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper.rb +5 -1
  3. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder.rb +10 -2
  4. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/association_select_field.rb +1 -1
  5. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/common_text_fields.rb +1 -1
  6. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/currency_field.rb +1 -1
  7. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/date_field.rb +1 -1
  8. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/fields_for.rb +1 -1
  9. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/file_field.rb +1 -1
  10. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/radio_select_field.rb +1 -1
  11. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/searchable_association_field.rb +1 -1
  12. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/select_field.rb +3 -2
  13. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/time_field.rb +1 -1
  14. data/{lib/eac → app/helpers/eac_rails_utils}/common_form_helper/form_builder/year_month_field.rb +1 -1
  15. data/app/helpers/eac_rails_utils/data_table_helper.rb +13 -0
  16. data/{lib/eac → app/helpers/eac_rails_utils}/data_table_helper/column.rb +1 -1
  17. data/{lib/eac → app/helpers/eac_rails_utils}/data_table_helper/data_table.rb +2 -2
  18. data/{lib/eac → app/helpers/eac_rails_utils}/data_table_helper/setup.rb +2 -2
  19. data/app/helpers/eac_rails_utils/links_helper.rb +5 -5
  20. data/{lib/eac → app/helpers/eac_rails_utils}/menus_helper.rb +5 -1
  21. data/{lib/eac → app/helpers/eac_rails_utils}/menus_helper/bootstrap_gui_builder.rb +1 -1
  22. data/{lib/eac → app/helpers/eac_rails_utils}/menus_helper/data_builder.rb +1 -1
  23. data/{lib/eac → app/helpers/eac_rails_utils}/menus_helper/gui_builder.rb +1 -1
  24. data/{lib/eac → app/validators/eac_rails_utils}/cpf_validator.rb +1 -1
  25. data/{lib/eac → app/validators/eac_rails_utils}/no_presence_validator.rb +1 -1
  26. data/config/locales/en.yml +8 -0
  27. data/config/locales/pt-BR.yml +8 -0
  28. data/lib/eac_rails_utils.rb +2 -39
  29. data/lib/eac_rails_utils/engine.rb +2 -0
  30. data/lib/{eac → eac_rails_utils}/htmlbeautifier.rb +1 -1
  31. data/lib/eac_rails_utils/models.rb +9 -0
  32. data/lib/eac_rails_utils/models/attribute_required.rb +43 -0
  33. data/lib/eac_rails_utils/models/fetch_errors.rb +92 -0
  34. data/lib/eac_rails_utils/models/inequality_queries.rb +39 -0
  35. data/lib/eac_rails_utils/models/tableless.rb +97 -0
  36. data/lib/eac_rails_utils/models/test_utils.rb +65 -0
  37. data/lib/eac_rails_utils/patches.rb +9 -0
  38. data/lib/eac_rails_utils/patches/action_controller_base.rb +2 -0
  39. data/lib/eac_rails_utils/patches/active_model_associations.rb +40 -0
  40. data/lib/eac_rails_utils/version.rb +1 -1
  41. data/test/dummy/app/assets/config/manifest.js +3 -0
  42. data/test/dummy/app/models/user.rb +4 -0
  43. data/test/dummy/config/application.rb +1 -1
  44. data/test/{lib/eac → helpers/eac_rails_utils}/common_form_helper_test.rb +2 -2
  45. data/test/{lib/eac → helpers/eac_rails_utils}/data_table_test_helper_test.rb +2 -2
  46. data/test/{app/helpers → helpers}/eac_rails_utils/formatter_helper_test.rb +0 -0
  47. data/test/lib/eac_rails_utils/{patches/model_attribute_required_test.rb → models/attribute_required_test.rb} +1 -0
  48. data/test/lib/eac_rails_utils/models/fetch_errors_test.rb +80 -0
  49. data/test/lib/eac_rails_utils/models/tableless_test.rb +25 -0
  50. data/test/{lib/eac → validators}/cpf_validator_test.rb +2 -2
  51. metadata +69 -66
  52. data/lib/eac/data_table_helper.rb +0 -13
  53. data/lib/eac/inequality_queries.rb +0 -37
  54. data/lib/eac/model.rb +0 -90
  55. data/lib/eac/test_utils.rb +0 -61
  56. data/lib/eac_rails_utils/patches/model_attribute_required.rb +0 -34
  57. data/lib/eac_rails_utils/patches/ofx_parser.rb +0 -43
  58. data/lib/eac_rails_utils/tableless_model.rb +0 -92
  59. data/test/lib/eac/model_test.rb +0 -78
  60. data/test/lib/eac/source_target_fixtures_test_files/a.source.html +0 -1
  61. data/test/lib/eac/source_target_fixtures_test_files/a.target.yaml +0 -1
  62. data/test/lib/eac/source_target_fixtures_test_files/b.source.html +0 -1
  63. data/test/lib/eac/source_target_fixtures_test_files/c.target.yaml +0 -1
  64. data/test/lib/eac_rails_utils/tableless_model_test.rb +0 -23
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EacRailsUtils
4
+ module Models
5
+ module FetchErrors
6
+ # Adiciona as mensagens de erro de record. As mensagens de uma coluna X em record
7
+ # serão adicionadas na coluna X em self. Se options[:default_column] for especificado
8
+ # as mensagens da coluna X de record em que X não existe em self serão adicionadas
9
+ # na coluna options[:default_column].
10
+ # Um array de colunas pode ser passado em options[:skip] de colunas em record que não
11
+ # terão suas falhas adicionadas.
12
+ def fetch_record_errors(record, options = {})
13
+ record.errors.keys.each do |column|
14
+ fetch_column_errors(record, column, column, options)
15
+ end
16
+ end
17
+
18
+ # Similar a fetch_record_errors, mas torna possível especificar, através de mapping,
19
+ # colunas-alvo em self com nomes diferentes das colunas-fonte em record.
20
+ # mapping tem o formato { record_column => self_column }.
21
+ def fetch_record_errors_by_mapping(record, mapping, options = {})
22
+ mapping.each do |record_column, self_column|
23
+ fetch_column_errors(record, record_column, self_column, options)
24
+ end
25
+ end
26
+
27
+ def fetch_column_errors(record, record_column, self_column, options = {})
28
+ return if options[:skip]&.include?(record_column)
29
+
30
+ record.errors[record_column].each do |message|
31
+ fetch_error_column_message(self_column, message, options[:default_column],
32
+ "#{record.class.human_attribute_name(record_column)}: ")
33
+ end
34
+ end
35
+
36
+ # Verifica se uma coluna existe.
37
+ def column?(column)
38
+ respond_to?(column) && respond_to?("#{column}=")
39
+ end
40
+
41
+ def save_or_raise
42
+ raise "Falha ao tentar salvar #{self.class.name}: #{errors_to_string}" unless save
43
+
44
+ self
45
+ end
46
+
47
+ private
48
+
49
+ def fetch_error_column_message(column, message, default_column, default_column_message_prefix)
50
+ build_self_columns_messages(column, message, default_column,
51
+ default_column_message_prefix).each do |k, v|
52
+ if column?(k)
53
+ add_error_message(k, v)
54
+ break
55
+ end
56
+ end
57
+ end
58
+
59
+ # Adiciona uma mensagem de erro a uma coluna somente se a coluna
60
+ # ainda não a possui
61
+ def add_error_message(column, message)
62
+ return if errors[column].include?(message)
63
+
64
+ errors.add(column, message)
65
+ end
66
+
67
+ # Produz uma lista de campos-mensagens, em ordem de preferência,
68
+ # que podem receber uma mensagem de falha.
69
+ def build_self_columns_messages(column, message, default_column,
70
+ default_column_message_prefix)
71
+ r = { column => message }
72
+ m = /^(.+)_id$/.match(column)
73
+ if m
74
+ r[m[1]] = message
75
+ else
76
+ r["#{column}_id"] = message
77
+ end
78
+ r[default_column] = "#{default_column_message_prefix}#{message}" if default_column
79
+ r
80
+ end
81
+
82
+ def errors_to_string
83
+ b = ''
84
+ errors.messages.each do |field, messages|
85
+ b += ' / ' if b != ''
86
+ b += field.to_s + ': ' + messages.to_s
87
+ end
88
+ b
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EacRailsUtils
4
+ module Models
5
+ # == Example:
6
+ #
7
+ # Note: model Product has a attribute "foo" Date, Time or Number:
8
+ #
9
+ # class Product
10
+ # include ::EacRailsUtils::Models::InequalityQueries
11
+ #
12
+ # add_inequality_queries(:foo)
13
+ # end
14
+ #
15
+ # This add the following scopes:
16
+ #
17
+ # Product.by_foo_gt(value) # Equivalent to Product.where("foo > ?", value)
18
+ # Product.by_foo_gteq(value) # Equivalent to Product.where("foo >= ?", value)
19
+ # Product.by_foo_lt(value) # Equivalent to Product.where("foo < ?", value)
20
+ # Product.by_foo_lteq(value) # Equivalent to Product.where("foo <= ?", value)
21
+ module InequalityQueries
22
+ class << self
23
+ def included(base)
24
+ base.extend(ClassMethods)
25
+ end
26
+ end
27
+
28
+ module ClassMethods
29
+ def add_inequality_queries(attribute)
30
+ %w[gt gteq lt lteq].each do |ineq|
31
+ scope "by_#{attribute}_#{ineq}", lambda { |v|
32
+ where(arel_table[attribute].send(ineq, v))
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_rails_utils/patches/active_model_associations'
4
+ require 'virtus'
5
+
6
+ module EacRailsUtils
7
+ module Models
8
+ class Tableless
9
+ include ActiveModel::Model
10
+ include Virtus.model
11
+ include ActiveModel::Associations
12
+
13
+ def initialize(values = {})
14
+ super(build_attributes(values))
15
+ end
16
+
17
+ def attributes=(values)
18
+ super(build_attributes(values))
19
+ end
20
+
21
+ # need hash like accessor, used internal Rails
22
+ def [](attr)
23
+ send(attr)
24
+ end
25
+
26
+ # need hash like accessor, used internal Rails
27
+ def []=(attr, value)
28
+ send("#{attr}=", value)
29
+ end
30
+
31
+ def save!
32
+ save || raise("#{self.class}.save failed: #{errors.messages}")
33
+ end
34
+
35
+ private
36
+
37
+ def build_attributes(values)
38
+ AttributesBuilder.new(self.class, values).to_attributes
39
+ end
40
+
41
+ class AttributesBuilder
42
+ DATE_TIME_FIELDS = %i[year month day hour min sec].freeze
43
+
44
+ def initialize(model_class, values)
45
+ @model_class = model_class
46
+ @values = {}
47
+ values.each { |k, v| add(k, v) }
48
+ end
49
+
50
+ def to_attributes
51
+ @values
52
+ end
53
+
54
+ private
55
+
56
+ def add(key, value)
57
+ array_attr = parse_array_attr_key(key)
58
+ if array_attr
59
+ array_value_set(array_attr, value)
60
+ else
61
+ @values[key] = value
62
+ end
63
+ end
64
+
65
+ def parse_array_attr_key(key)
66
+ m = /\A(.+)\(([0-9]+)(.)\)\z/.match(key)
67
+ return unless m
68
+
69
+ ::OpenStruct.new(key: m[1], index: m[2].to_i - 1, converter: array_value_converter(m[3]))
70
+ end
71
+
72
+ def array_value_set(array_attr, value)
73
+ @values[array_attr.key] ||= {}
74
+ @values[array_attr.key].merge!(
75
+ DATE_TIME_FIELDS[array_attr.index] => value.send(array_attr.converter)
76
+ )
77
+ end
78
+
79
+ def array_value_converter(str_type)
80
+ case str_type
81
+ when 'i'
82
+ 'to_i'
83
+ else
84
+ raise "Unknown array type: \"#{str_type}\""
85
+ end
86
+ end
87
+
88
+ def date_time_attribute?(key)
89
+ attr = @model_class.attributes[key]
90
+ return false unless attr
91
+
92
+ raise attr.to_s
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EacRailsUtils
4
+ module Models
5
+ module TestUtils
6
+ # Add more helper methods to be used by all tests here...
7
+ def valid_invalid_column_values_test(record, column, valid_values, invalid_values)
8
+ valid_values.each do |v|
9
+ record.send("#{column}=", v)
10
+ assert record.valid?,
11
+ "#{record.errors.messages}, #{column} = #{v.inspect} should be valid"
12
+ end
13
+ invalid_values.each do |v|
14
+ record.send("#{column}=", v)
15
+ assert_not record.valid?, "#{column} = #{v.inspect} should be invalid"
16
+ end
17
+ end
18
+
19
+ # Verifica falhas em campos específicos de um record
20
+ def assert_record_errors(record, fields_without_error, fields_with_error)
21
+ fields_without_error.each do |c|
22
+ assert record.errors[c].empty?,
23
+ "Column: #{c} should not have errors (#{record.errors[c]})"
24
+ end
25
+ fields_with_error. each do |c|
26
+ assert_not record.errors[c].empty?, "Column: #{c} should have errors"
27
+ end
28
+ end
29
+
30
+ # Verifica, campo por campo, se invalida o registro.
31
+ def assert_column_changes(ppp, expected_valid_result, changes)
32
+ changes.each do |k, v|
33
+ ppp.send("#{k}=", v)
34
+ assert_equal expected_valid_result, ppp.valid?,
35
+ "\"#{k}\" change should be " + (expected_valid_result ? 'valid' : 'invalid')
36
+ assert_not ppp.errors[k].empty? unless expected_valid_result
37
+ ppp.restore_attributes
38
+ end
39
+ end
40
+
41
+ # Ex.: attrs = {a: 1, b: 2} resulta em
42
+ # [{a: nil, b: nil}, {a: 1, b: nil}, {a: nil, b: 2}, {a: 1, b: 2}].
43
+ def all_combinations(attrs)
44
+ combs = [{}]
45
+ attrs.each do |attr_name, value|
46
+ combs = all_combinations_new_combination(attr_name, value, combs)
47
+ end
48
+ combs
49
+ end
50
+
51
+ def all_combinations_new_combination(attr_name, value, combs)
52
+ new_comb = []
53
+ assert_not value.nil?, "#{attr_name}=#{value}"
54
+ [nil, value].each do |vv|
55
+ combs.each do |c|
56
+ cc = c.dup
57
+ cc[attr_name] = vv
58
+ new_comb << cc
59
+ end
60
+ end
61
+ new_comb
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_ruby_utils/require_sub'
4
+
5
+ module EacRailsUtils
6
+ module Patches
7
+ ::EacRubyUtils.require_sub __FILE__
8
+ end
9
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'action_controller/base'
4
+
3
5
  module EacRailsUtils
4
6
  module Patches
5
7
  module ActionControllerBasePatch
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model/associations/hooks'
4
+ require 'activemodel/associations'
5
+
6
+ module EacRailsUtils
7
+ module Patches
8
+ module ActiveModelAssociations
9
+ module ScopeExtensionPatch
10
+ def add_constraints(scope, owner, association_klass, *extra_args)
11
+ if extra_args.any?
12
+ refl = extra_args.first
13
+ if refl.options[:active_model]
14
+ target_ids = refl.options[:target_ids]
15
+ return scope.where(id: owner[target_ids])
16
+ end
17
+ end
18
+
19
+ super
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ module ActiveModel
27
+ module Associations
28
+ module Hooks
29
+ def self.init
30
+ return unless ::Rails.version < '5'
31
+
32
+ ActiveSupport.on_load(:active_record) do
33
+ ActiveRecord::Associations::AssociationScope.prepend(
34
+ ::EacRailsUtils::Patches::ActiveModelAssociations::ScopeExtensionPatch
35
+ )
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EacRailsUtils
4
- VERSION = '0.10.1'
4
+ VERSION = '0.11.4'
5
5
  end
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../javascripts .js
3
+ //= link_directory ../stylesheets .css
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'eac_rails_utils/models/attribute_required'
4
+
3
5
  class User < ActiveRecord::Base
6
+ include ::EacRailsUtils::Models::AttributeRequired
7
+
4
8
  belongs_to :job
5
9
 
6
10
  validates :job, presence: true
@@ -9,6 +9,6 @@ require 'eac_rails_utils'
9
9
 
10
10
  module Dummy
11
11
  class Application < Rails::Application
12
- config.active_record.raise_in_transactional_callbacks = true
12
+ config.active_record.raise_in_transactional_callbacks = true if ::Rails.version < '5'
13
13
  end
14
14
  end
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'test_helper'
4
4
 
5
- module Eac
5
+ module EacRailsUtils
6
6
  class CommonFormHelperTest < ActionView::TestCase
7
- include Eac::CommonFormHelper
7
+ include ::EacRailsUtils::CommonFormHelper
8
8
 
9
9
  setup do
10
10
  reset_test_database
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'test_helper'
4
4
 
5
- module Eac
5
+ module EacRailsUtils
6
6
  class DataTableTestHelperTest < ActionView::TestCase
7
- include ::Eac::DataTableHelper
7
+ include ::EacRailsUtils::DataTableHelper
8
8
 
9
9
  class Person
10
10
  attr_reader :name, :age, :job
@@ -32,6 +32,7 @@ module EacRailsUtils
32
32
 
33
33
  class ActiveModelStub
34
34
  include ActiveModel::Model
35
+ include ::EacRailsUtils::Models::AttributeRequired
35
36
 
36
37
  attr_accessor :name, :age
37
38
  validates :name, presence: true
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ module EacRailsUtils
6
+ module Models
7
+ class FetchErrorsTest < ActiveSupport::TestCase
8
+ class M1
9
+ include ActiveModel::Model
10
+ include EacRailsUtils::Models::FetchErrors
11
+ attr_accessor :name, :age, :account, :country_id, :other
12
+ end
13
+
14
+ class M2
15
+ include ActiveModel::Model
16
+ attr_accessor :name, :myage, :account_id, :country
17
+
18
+ validate :my_validate
19
+
20
+ def my_validate
21
+ errors.add(:name, 'NAME_ERROR')
22
+ errors.add(:myage, 'MYAGE_ERROR')
23
+ errors.add(:account_id, 'ACCOUNT_ID_ERROR')
24
+ errors.add(:country, 'COUNTRY_ERROR')
25
+ end
26
+ end
27
+
28
+ def setup
29
+ reset_m1
30
+ reset_m2
31
+ end
32
+
33
+ def test_fetch_column_errors
34
+ @m1.fetch_column_errors(@m2, :myage, :age)
35
+ assert_equal @m2.errors[:myage], @m1.errors[:age]
36
+ end
37
+
38
+ def test_fetch_record_errors
39
+ @m1.fetch_record_errors(@m2)
40
+ { name: :name, account_id: :account, country: :country_id }.each do |c2, c1|
41
+ assert_equal @m2.errors[c2], @m1.errors[c1], "c2: #{c2}, c1: #{c1}"
42
+ end
43
+ assert @m1.errors[:age].empty?
44
+ end
45
+
46
+ def test_fetch_record_errors_with_default_column
47
+ @m1.fetch_record_errors(@m2, default_column: :other)
48
+ assert_equal @m2.errors[:name], @m1.errors[:name]
49
+ assert @m1.errors[:age].empty?
50
+ assert_equal ['Myage: MYAGE_ERROR'], @m1.errors[:other]
51
+ end
52
+
53
+ def test_fetch_record_errors_with_skip_option
54
+ @m1.fetch_record_errors(@m2, skip: [:name])
55
+ assert @m1.errors[:name].empty?
56
+ assert @m1.errors[:age].empty?
57
+ end
58
+
59
+ def test_fetch_record_errors_by_mapping
60
+ @m1.fetch_record_errors_by_mapping(@m2, name: :name, myage: :age)
61
+ assert_equal @m2.errors[:name], @m1.errors[:name]
62
+ assert_equal @m2.errors[:myage], @m1.errors[:age]
63
+ end
64
+
65
+ private
66
+
67
+ def reset_m1
68
+ @m1 = M1.new
69
+ assert @m1.errors.empty?
70
+ end
71
+
72
+ def reset_m2
73
+ @m2 = M2.new
74
+ assert_not @m2.valid?
75
+ assert_not @m2.errors[:name].empty?
76
+ assert_not @m2.errors[:myage].empty?
77
+ end
78
+ end
79
+ end
80
+ end