eac_rails_utils 0.0.1

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 (57) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +18 -0
  3. data/lib/assets/javascripts/currency_field.js +21 -0
  4. data/lib/assets/javascripts/eac_rails_utils.js +6 -0
  5. data/lib/assets/javascripts/input_searchable.js +78 -0
  6. data/lib/assets/javascripts/jMenu.jquery.min.js +12 -0
  7. data/lib/assets/javascripts/jquery.maskMoney.js +409 -0
  8. data/lib/assets/stylesheets/autocomplete.scss +33 -0
  9. data/lib/assets/stylesheets/bootstrap3-dropdown.scss +47 -0
  10. data/lib/assets/stylesheets/eac_rails_utils.scss +44 -0
  11. data/lib/assets/stylesheets/jmenu.scss +78 -0
  12. data/lib/eac/common_form_helper.rb +37 -0
  13. data/lib/eac/common_form_helper/form_builder.rb +88 -0
  14. data/lib/eac/common_form_helper/form_builder/association_select_field.rb +40 -0
  15. data/lib/eac/common_form_helper/form_builder/common_text_fields.rb +18 -0
  16. data/lib/eac/common_form_helper/form_builder/currency_field.rb +39 -0
  17. data/lib/eac/common_form_helper/form_builder/date_field.rb +20 -0
  18. data/lib/eac/common_form_helper/form_builder/fields_for.rb +44 -0
  19. data/lib/eac/common_form_helper/form_builder/radio_select_field.rb +44 -0
  20. data/lib/eac/common_form_helper/form_builder/searchable_association_field.rb +77 -0
  21. data/lib/eac/cpf_validator.rb +60 -0
  22. data/lib/eac/formatter_helper.rb +27 -0
  23. data/lib/eac/htmlbeautifier.rb +25 -0
  24. data/lib/eac/menus_helper.rb +17 -0
  25. data/lib/eac/menus_helper/bootstrap_gui_builder.rb +90 -0
  26. data/lib/eac/menus_helper/data_builder.rb +57 -0
  27. data/lib/eac/menus_helper/gui_builder.rb +51 -0
  28. data/lib/eac/model.rb +87 -0
  29. data/lib/eac/simple_cache.rb +29 -0
  30. data/lib/eac/source_target_fixtures.rb +51 -0
  31. data/lib/eac_rails_utils.rb +29 -0
  32. data/lib/eac_rails_utils/patches/model_attribute_required.rb +31 -0
  33. data/lib/eac_rails_utils/rails/engine.rb +5 -0
  34. data/lib/eac_rails_utils/version.rb +3 -0
  35. data/test/dummy/Rakefile +6 -0
  36. data/test/dummy/app/models/job.rb +4 -0
  37. data/test/dummy/app/models/user.rb +7 -0
  38. data/test/dummy/config.ru +4 -0
  39. data/test/dummy/config/application.rb +12 -0
  40. data/test/dummy/config/boot.rb +4 -0
  41. data/test/dummy/config/database.yml +5 -0
  42. data/test/dummy/config/environment.rb +5 -0
  43. data/test/dummy/config/environments/test.rb +42 -0
  44. data/test/dummy/config/routes.rb +8 -0
  45. data/test/dummy/config/secrets.yml +22 -0
  46. data/test/dummy/db/migrate/20160415125333_create_users.rb +9 -0
  47. data/test/dummy/db/migrate/20160415143123_create_jobs.rb +7 -0
  48. data/test/dummy/db/migrate/20160415143229_add_job_to_users.rb +5 -0
  49. data/test/dummy/db/schema.rb +25 -0
  50. data/test/lib/eac/common_form_helper_test.rb +31 -0
  51. data/test/lib/eac/cpf_validator_test.rb +33 -0
  52. data/test/lib/eac/formatter_helper_test.rb +19 -0
  53. data/test/lib/eac/model_test.rb +76 -0
  54. data/test/lib/eac/simple_cache_test.rb +56 -0
  55. data/test/lib/eac_rails_utils/patches/model_attribute_required_test.rb +39 -0
  56. data/test/test_helper.rb +11 -0
  57. metadata +189 -0
@@ -0,0 +1,44 @@
1
+ module Eac
2
+ module CommonFormHelper
3
+ class FormBuilder
4
+ module FieldsFor
5
+ def fields_for(association, &block)
6
+ fieldset(association) do
7
+ nested_fields(association, &block) << add_link(association)
8
+ end
9
+ end
10
+
11
+ private
12
+
13
+ def nested_fields(association, &block)
14
+ form.nested_fields_for(association) do |nested_form|
15
+ helper.content_tag(:div, class: 'nested_form_row') do
16
+ helper.capture(FormBuilder.new(nested_form, helper), &block) <<
17
+ remove_link(nested_form)
18
+ end
19
+ end
20
+ end
21
+
22
+ def add_link(association)
23
+ form.add_nested_fields_link(association, 'Adicionar', class: 'btn btn-primary',
24
+ role: 'button')
25
+ end
26
+
27
+ def remove_link(nested_form)
28
+ nested_form.remove_nested_fields_link('Remover', class: 'btn btn-danger',
29
+ role: 'button')
30
+ end
31
+
32
+ def fieldset(association, &block)
33
+ helper.content_tag(:fieldset, class: 'nested_form') do
34
+ helper.content_tag(:legend, fieldset_legend(association)) << block.call
35
+ end
36
+ end
37
+
38
+ def fieldset_legend(association)
39
+ I18n.t("helpers.label.#{form.object.class.name.underscore}.#{association}")
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ module Eac
2
+ module CommonFormHelper
3
+ class FormBuilder
4
+ module RadioSelectField
5
+ def radio_select_field(field_name, radios_values, options = {})
6
+ field(field_name, options) do
7
+ radios(field_name, radios_values)
8
+ end
9
+ end
10
+
11
+ private
12
+
13
+ def radios(field_name, radios_values)
14
+ b = ActiveSupport::SafeBuffer.new
15
+ radios_values.each do |r|
16
+ b << radio(field_name, r[0], r[1])
17
+ end
18
+ b
19
+ end
20
+
21
+ def radio(field_name, value, label)
22
+ helper.content_tag(:div, class: 'radio') do
23
+ helper.content_tag(:label) do
24
+ form.radio_button(field_name, value) << label
25
+ end
26
+ end
27
+ end
28
+
29
+ def extract_select_options(options)
30
+ options.extract!(:prompt, :include_blank)
31
+ end
32
+
33
+ def extract_association_key(field_name, options, key, method)
34
+ return options.delete(key) if options.key?(key)
35
+ if model_instance.class.respond_to?(:reflect_on_association)
36
+ return model_instance.class.reflect_on_association(field_name).send(method)
37
+ end
38
+ fail "#{model_instance.class} não possui um método \"reflect_on_association\". " \
39
+ "Defina explicitamente a opção :#{key}"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,77 @@
1
+ module Eac
2
+ module CommonFormHelper
3
+ class FormBuilder
4
+ class SearchableAssociationField
5
+ def initialize(form_builder, field_name, options)
6
+ @form_builder = form_builder
7
+ @field_name = field_name
8
+ @options = options
9
+ end
10
+
11
+ def hidden_input
12
+ @form_builder.form.hidden_field(hidden_input_name, id: hidden_input_id)
13
+ end
14
+
15
+ def visible_input
16
+ @form_builder.helper.text_field_tag(visible_input_name, '', id: visible_input_id,
17
+ class: 'form-control')
18
+ end
19
+
20
+ def javascript_tag
21
+ @form_builder.helper.content_tag(:script) do
22
+ @form_builder.helper.raw("new InputSearchable(#{json_options});")
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def hidden_input_id
29
+ @hidden_input_id ||= SecureRandom.hex(5)
30
+ end
31
+
32
+ def hidden_input_name
33
+ "#{@field_name}_id"
34
+ end
35
+
36
+ def visible_input_id
37
+ @visible_input_id ||= SecureRandom.hex(5)
38
+ end
39
+
40
+ def visible_input_name
41
+ "#{@field_name}_search"
42
+ end
43
+
44
+ def association_column
45
+ @form_builder.model_instance && @form_builder.model_instance.send(@field_name)
46
+ end
47
+
48
+ def initial_id
49
+ return association_column.id if association_column
50
+ ''
51
+ end
52
+
53
+ def initial_label
54
+ return association_column.to_s if association_column
55
+ return params[visible_input_name] if params.key?(visible_input_name)
56
+ ''
57
+ end
58
+
59
+ def params
60
+ @form_builder.helper.params
61
+ end
62
+
63
+ def url
64
+ @options[:url]
65
+ end
66
+
67
+ def json_options
68
+ r = {}
69
+ [:hidden_input_id, :visible_input_id, :initial_id, :initial_label, :url].each do |k|
70
+ r[k] = send(k)
71
+ end
72
+ r.to_json
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,60 @@
1
+ module Eac
2
+ class CpfValidator < ActiveModel::EachValidator
3
+ def validate_each(record, attribute, value)
4
+ return if Cpf.new(value).valid?
5
+ record.errors[attribute] << (options[:message] ||
6
+ 'CPF inválido (9 caracteres, somente dígitos)')
7
+ end
8
+
9
+ class Cpf
10
+ def initialize(input)
11
+ @input = input
12
+ end
13
+
14
+ def valid?
15
+ return false if input_invalid?
16
+ digito_verificador1_calculo == values[9] && digito_verificador2_calculo == values[10]
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :input
22
+
23
+ def input_invalid?
24
+ input.nil? || digits.length != 11 || digits.length != input.length || null?
25
+ end
26
+
27
+ def null?
28
+ %w(12345678909 11111111111 22222222222 33333333333 44444444444 55555555555
29
+ 66666666666 77777777777 88888888888 99999999999 00000000000).member?(digits.join)
30
+ end
31
+
32
+ def digits
33
+ @digits ||= input.scan(/[0-9]/)
34
+ end
35
+
36
+ def values
37
+ @values ||= digits.collect(&:to_i)
38
+ end
39
+
40
+ def digito_verificador1_calculo
41
+ digito_verificador_calculo(9, 10)
42
+ end
43
+
44
+ def digito_verificador2_calculo
45
+ digito_verificador_calculo(10, 11)
46
+ end
47
+
48
+ def digito_verificador_calculo(valores_count, coeficiente_inicial)
49
+ s = 0
50
+ c = coeficiente_inicial
51
+ (0..valores_count - 1).each do |i|
52
+ s += values[i] * c
53
+ c -= 1
54
+ end
55
+ s -= (11 * (s / 11))
56
+ (s == 0 || s == 1) ? 0 : 11 - s
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,27 @@
1
+ module Eac
2
+ module FormatterHelper
3
+ include ActionView::Helpers::NumberHelper
4
+
5
+ def format_real(value)
6
+ number_to_currency(
7
+ value,
8
+ unit: 'R$ ',
9
+ separator: ',',
10
+ delimiter: '.',
11
+ raise: true
12
+ )
13
+ end
14
+
15
+ def format_percentage(float_value)
16
+ number_to_percentage(float_value * 100, precision: 0)
17
+ end
18
+
19
+ def brl_currency_to_float(currency)
20
+ currency.to_s.gsub(/[R$ .]/, '').tr(',', '.').to_f
21
+ end
22
+
23
+ def format_cep(cep)
24
+ "#{cep[0, 5]}-#{cep[5, 3]}"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ require 'htmlbeautifier'
2
+
3
+ module Eac
4
+ class Htmlbeautifier
5
+ def self.beautify(string)
6
+ ::HtmlBeautifier.beautify(string, tab_stops: 2) + "\n"
7
+ end
8
+
9
+ def self.file_beautified?(file)
10
+ input = File.read(file)
11
+ input == beautify(input)
12
+ end
13
+
14
+ def self.beautify_file(file)
15
+ input = File.read(file)
16
+ output = beautify(input)
17
+ if input == output
18
+ false
19
+ else
20
+ File.write(file, output)
21
+ true
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,17 @@
1
+ module Eac
2
+ module MenusHelper
3
+ def dropdown_menu(entries)
4
+ entries = DataBuilder.new(self).build(entries)
5
+ return nil unless entries
6
+ id = SecureRandom.hex(5)
7
+ GuiBuilder.new(self).build(entries, id: id, class: 'jMenu') <<
8
+ content_tag(:script) { raw("$(document).ready(function(){$('\##{id}').jMenu();});") }
9
+ end
10
+
11
+ def bootstrap_dropdown_menu(entries, options = {})
12
+ entries = DataBuilder.new(self).build(entries)
13
+ return nil unless entries
14
+ BootstrapGuiBuilder.new(self, options).build(entries)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,90 @@
1
+ module Eac
2
+ module MenusHelper
3
+ # http://bootsnipp.com/snippets/featured/multi-level-dropdown-menu-bs3
4
+ class BootstrapGuiBuilder
5
+ def initialize(view, options = {})
6
+ @view = view
7
+ @options = options
8
+ end
9
+
10
+ def build(entries)
11
+ fail "Argument \"entries\" is not a array" unless entries.is_a?(Array)
12
+ @view.content_tag(:ul, class: "nav navbar-nav #{@options[:class]}".strip) do
13
+ menu_entries(entries)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def menu_entries(entries)
20
+ b = ActiveSupport::SafeBuffer.new
21
+ entries.map { |v| b << menu_entry(v) }
22
+ b
23
+ end
24
+
25
+ def menu_entry(entry)
26
+ if entry[:type] == :group
27
+ menu_group(entry)
28
+ elsif entry[:type] == :item
29
+ menu_item(entry)
30
+ else
31
+ fail "Unknown menu entry type: \"#{entry[:type]}\""
32
+ end
33
+ end
34
+
35
+ def menu_group(entry)
36
+ if entry[:level] == 0
37
+ menu_group_root(entry)
38
+ else
39
+ menu_group_sub(entry)
40
+ end
41
+ end
42
+
43
+ def menu_group_root(entry)
44
+ @view.content_tag(:li, class: 'dropdown') do
45
+ menu_group_root_button(entry) << menu_group_root_children(entry)
46
+ end
47
+ end
48
+
49
+ def menu_group_root_button(entry)
50
+ @view.content_tag(:a, :role => 'button', 'data-toggle' => 'dropdown',
51
+ :class => "btn #{@options[:button_class]}",
52
+ :'data-target' => '#') do
53
+ ActiveSupport::SafeBuffer.new(entry[:label]) << ' ' << @view.tag(:span, class: 'caret')
54
+ end
55
+ end
56
+
57
+ def menu_group_root_children(entry)
58
+ @view.content_tag(:ul, class: 'dropdown-menu multi-level', role: 'menu',
59
+ 'aria-labelledby': 'dropdownMenu') do
60
+ menu_entries(entry[:children])
61
+ end
62
+ end
63
+
64
+ def menu_group_sub(entry)
65
+ @view.content_tag(:li, class: 'dropdown-submenu') do
66
+ @view.link_to(entry[:label], '#', tabindex: -1) <<
67
+ @view.content_tag(:ul, class: 'dropdown-menu') do
68
+ menu_entries(entry[:children])
69
+ end
70
+ end
71
+ end
72
+
73
+ def menu_item(entry)
74
+ @view.content_tag(:li) do
75
+ @view.link_to(entry[:label], entry[:path], menu_item_options(entry))
76
+ end
77
+ end
78
+
79
+ def menu_item_options(entry)
80
+ options = entry[:options].dup
81
+ if options.key?(:link_method)
82
+ options[:method] = options[:link_method]
83
+ options.delete(:link_method)
84
+ end
85
+ options[:class] = "#{@options[:button_class]}".strip if entry[:level] == 0
86
+ options
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,57 @@
1
+ module Eac
2
+ module MenusHelper
3
+ class DataBuilder
4
+ def initialize(view)
5
+ @view = view
6
+ end
7
+
8
+ def build(entries)
9
+ build_entries(entries, 0)
10
+ end
11
+
12
+ private
13
+
14
+ def build_entries(entries, level)
15
+ fail 'Argument "entries" is not a hash' unless entries.is_a?(Hash)
16
+ r = entries.map { |k, v| build_entry(k, v, level) }.select { |e| e }
17
+ r.empty? ? nil : r
18
+ end
19
+
20
+ def build_entry(key, value, level)
21
+ if value.is_a?(Hash)
22
+ build_group(key, value, level)
23
+ else
24
+ build_item(key, value, level)
25
+ end
26
+ end
27
+
28
+ def build_group(label, menu_entries, level)
29
+ e = build_entries(menu_entries, level + 1)
30
+ return nil unless e
31
+ { type: :group, label: label, children: e, level: level }
32
+ end
33
+
34
+ def build_item(label, value, level)
35
+ path, options = menu_item_options(value)
36
+ return nil unless can_access_path?(path, options[:link_method])
37
+ { type: :item, label: label, path: path, options: options, level: level }
38
+ end
39
+
40
+ def menu_item_options(item_value)
41
+ if item_value.is_a?(Array)
42
+ [item_value[0], item_value[1] || {}]
43
+ else
44
+ [item_value, {}]
45
+ end
46
+ end
47
+
48
+ def can_access_path?(path, method)
49
+ if @view.respond_to?(:'can_by_path?')
50
+ @view.can_by_path?(path, method)
51
+ else
52
+ true
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end