eac_rails_utils 0.10.1 → 0.11.4

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