eac_rails_utils 0.0.1

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