normatron 0.0.2

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.
@@ -0,0 +1,20 @@
1
+ Copyright 2012 Fernando Rodrigues da Silva
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ = Normatron
2
+
3
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Normatron'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ Bundler::GemHelper.install_tasks
24
+
25
+ require 'rake/testtask'
26
+
27
+ Rake::TestTask.new(:test) do |t|
28
+ t.libs << 'lib'
29
+ t.libs << 'test'
30
+ t.pattern = 'test/**/*_test.rb'
31
+ t.verbose = false
32
+ end
33
+
34
+
35
+ task :default => :test
@@ -0,0 +1,4 @@
1
+ require "normatron/conversors"
2
+ require "normatron/active_record"
3
+
4
+ ActiveRecord::Base.send :include, Normatron::ActiveRecord
@@ -0,0 +1,64 @@
1
+ require "active_record"
2
+
3
+ module Normatron
4
+ module ActiveRecord
5
+ include Conversors
6
+
7
+ def self.included(base)
8
+ base.instance_eval do
9
+ extend ClassMethods
10
+
11
+ before_validation :normalize_attributes
12
+
13
+ class << self
14
+ attr_accessor :standardize_options
15
+ end
16
+ end
17
+ end
18
+
19
+ module ClassMethods
20
+ def normalize(*args)
21
+ # Extract options
22
+ self.standardize_options ||= {}
23
+ options = args.extract_options!
24
+
25
+ methods = []
26
+ if options.empty? # Default standardization
27
+ methods << [:trim, :strip, :nillify]
28
+ elsif options.has_key? :with
29
+ methods << options[:with]
30
+ else
31
+ raise "Wrong normalization option for #{attribute}, use :with instead."
32
+ end
33
+
34
+ # Make a prettier array
35
+ methods = methods.flatten.compact
36
+ methods.map! { |v| v = v.to_sym }
37
+
38
+ # Add normalization methods to call
39
+ args.each do |attribute|
40
+ standardize_options[attribute] = methods
41
+ end
42
+ end
43
+ end
44
+
45
+ def normalize_attributes
46
+ options = self.class.standardize_options
47
+
48
+ options.each do |attribute, methods|
49
+ value = send("#{attribute}_before_type_cast") || send(attribute)
50
+
51
+ methods.each do |method|
52
+ # Skip if value is nil originally or the method 'nullify' was called before
53
+ value = convert(method, value) unless value.nil?
54
+ if value == :no_method
55
+ raise ArgumentError, "Method :#{method} cannot be resolved.
56
+ Check options for #{attribute} in #{klass}", caller
57
+ end
58
+ end
59
+
60
+ write_attribute attribute, value
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,91 @@
1
+ require "i18n"
2
+ require "active_support/all"
3
+
4
+ module Normatron
5
+ module Conversors
6
+
7
+ @@MB_CHARS_METHODS = [:upcase, :downcase, :capitalize, :lstrip, :rstrip, :strip, :titlecase, :titleize]
8
+ @@SELF_METHODS = [:nillify, :nullify, :nil, :trim, :currency, :integer, :float, :postal_code, :phone, :digits, :phrase]
9
+
10
+ def convert(method, value)
11
+ if @@MB_CHARS_METHODS.include? method
12
+ value.mb_chars.send(method).to_s
13
+ elsif @@SELF_METHODS.include? method
14
+ send("convert_#{method}", value)
15
+ else
16
+ :no_method
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ # Return nil if value is blank or else value itself.
23
+ def convert_nillify(value)
24
+ value.blank? ? nil : value
25
+ end
26
+ alias :convert_nil :convert_nillify
27
+ alias :convert_nullify :convert_nillify
28
+
29
+ # Remove repeated spaces from the string.
30
+ def convert_trim(value)
31
+ value.mb_chars.to_s.gsub(/\p{Zs}+/u, ' ')
32
+ end
33
+
34
+ def convert_currency(value)
35
+ convert_number value, :currency
36
+ end
37
+
38
+ def convert_float(value)
39
+ convert_number value, :float
40
+ end
41
+
42
+ def convert_integer(value)
43
+ convert_number value
44
+ end
45
+
46
+ def convert_number(value, type = :integer)
47
+ return value unless value.is_a?(String) && value.present?
48
+
49
+ # Find the first number in the sequence
50
+ first_number_position = value.index(/\d/)
51
+ return unless first_number_position # Do nothing if it's don't have any number
52
+
53
+ # Is a negative number?
54
+ negative = value[0..first_number_position].include?("-")
55
+
56
+ # Decimal separator on the current locale
57
+ separator = I18n.t "number#{ '.currency' if type == :currency }.format.separator"
58
+
59
+ # Amount of decimal places
60
+ separator_position = value.rindex(separator)
61
+ chars_until_separator = separator_position + 1 rescue value.size
62
+ decimal_places = value.size - chars_until_separator
63
+
64
+ # Build number
65
+ res = convert_digits(value).to_f
66
+ res *= -1 if negative
67
+ res /= 10 ** decimal_places
68
+ res = res.to_i if type == :integer
69
+
70
+ res
71
+ end
72
+
73
+ def convert_postal_code(value)
74
+ res = convert_digits value
75
+ res.size == 8 ? "%s-%s" % [res[0..4], res[5..7]] : value
76
+ end
77
+
78
+ def convert_phone(value)
79
+ res = convert_digits value
80
+ res.size == 10 ? "(%s) %s-%s" % [res[0..1], res[2..5], res[6..9]] : value
81
+ end
82
+
83
+ def convert_digits(value)
84
+ value.to_s.gsub(/[^\d]/, '')
85
+ end
86
+
87
+ def convert_phrase(value)
88
+ convert(:trim, convert(:strip, value))
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,3 @@
1
+ module Normatron
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :normatron do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Normatron do
6
+ before :each do
7
+ TestModel.standardize_options = {}
8
+ end
9
+
10
+ describe "Conversors" do
11
+ it :capitalize do
12
+ TestModel.normalize :string_field, :with => :capitalize
13
+
14
+ m = TestModel.create :string_field => "áb c, 1 2 3 DEF GHI i oz "
15
+ m.string_field.should == "Áb c, 1 2 3 def ghi i oz "
16
+ end
17
+
18
+ it :digits do
19
+ TestModel.normalize :string_field, :with => :digits
20
+
21
+ m = TestModel.create :string_field => " 1a 2b 3c 4d 5e 6f "
22
+ m.string_field.should == "123456"
23
+ end
24
+
25
+ it :downcase do
26
+ TestModel.normalize :string_field, :with => :downcase
27
+
28
+ m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
29
+ m.string_field.should == " a b c, 1 2 3 def ghi i oz "
30
+ end
31
+
32
+ it :phone do
33
+ TestModel.normalize :string_field, :with => :phone
34
+
35
+ m = TestModel.create :string_field => "(99) 9999-9999"
36
+ m.string_field.should == "(99) 9999-9999"
37
+
38
+ m = TestModel.create :string_field => "9999999999"
39
+ m.string_field.should == "(99) 9999-9999"
40
+
41
+ m = TestModel.create :string_field => "999999999"
42
+ m.string_field.should == "999999999"
43
+ end
44
+
45
+ it :phrase do
46
+ TestModel.normalize :string_field, :with => :phrase
47
+
48
+ m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
49
+ m.string_field.should == "a b c, 1 2 3 DEF GHI i oz"
50
+ end
51
+
52
+ it :postal_code do
53
+ TestModel.normalize :string_field, :with => :postal_code
54
+
55
+ m = TestModel.create :string_field => "88888-888"
56
+ m.string_field.should == "88888-888"
57
+
58
+ m = TestModel.create :string_field => "88888888"
59
+ m.string_field.should == "88888-888"
60
+
61
+ m = TestModel.create :string_field => "8888888"
62
+ m.string_field.should == "8888888"
63
+ end
64
+
65
+ it :strip do
66
+ TestModel.normalize :string_field, :with => :strip
67
+
68
+ m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
69
+ m.string_field.should == "a b c, 1 2 3 DEF GHI i oz"
70
+ end
71
+
72
+ it :titlecase do
73
+ TestModel.normalize :string_field, :with => :titlecase
74
+
75
+ m = TestModel.create :string_field => " aé áb c, 1 2 3 DEF GHI i oz "
76
+ m.string_field.should == " Aé Áb C, 1 2 3 Def Ghi I Oz "
77
+ end
78
+
79
+ it :upcase do
80
+ TestModel.normalize :string_field, :with => :upcase
81
+
82
+ m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
83
+ m.string_field.should == " A B C, 1 2 3 DEF GHI I OZ "
84
+ end
85
+
86
+
87
+
88
+ it :nillify do
89
+ TestModel.normalize :string_field, :with => :nillify
90
+
91
+ m = TestModel.create :string_field => " "
92
+ m.string_field.should == nil
93
+ end
94
+
95
+ it :trim do
96
+ TestModel.normalize :string_field, :with => :trim
97
+
98
+ m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
99
+ m.string_field.should == " a b c, 1 2 3 DEF GHI i oz "
100
+ end
101
+
102
+ it :lstrip do
103
+ TestModel.normalize :string_field, :with => :lstrip
104
+
105
+ m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
106
+ m.string_field.should == "a b c, 1 2 3 DEF GHI i oz "
107
+ end
108
+
109
+ it :rstrip do
110
+ TestModel.normalize :string_field, :with => :rstrip
111
+
112
+ m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
113
+ m.string_field.should == " a b c, 1 2 3 DEF GHI i oz"
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,6 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :test_models do |t|
3
+ t.string :string_field
4
+ t.integer :integer_field
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ require "rspec"
2
+ require "normatron"
3
+
4
+ ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => ":memory:"
5
+
6
+ load "schema.rb"
7
+
8
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
@@ -0,0 +1,3 @@
1
+ class TestModel < ActiveRecord::Base
2
+ attr_accessible :string_field, :integer_field
3
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: normatron
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Fernando Rodrigues da Silva
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 3.0.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: sqlite3
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: 2.0.0
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.0.0
62
+ description: ! " Normatron is a Rails plugin that helps normalize ActiveRecord
63
+ attributes.\n Operations such as lowercase an e-mail address or format a phone
64
+ number before model validations,\n can be made easily using this plugin.\n"
65
+ email:
66
+ - fernandors87@hotmail.com
67
+ executables: []
68
+ extensions: []
69
+ extra_rdoc_files: []
70
+ files:
71
+ - lib/normatron/active_record.rb
72
+ - lib/normatron/conversors.rb
73
+ - lib/normatron/version.rb
74
+ - lib/tasks/normatron_tasks.rake
75
+ - lib/normatron.rb
76
+ - MIT-LICENSE
77
+ - Rakefile
78
+ - README.rdoc
79
+ - spec/support/test_model.rb
80
+ - spec/normatron_spec.rb
81
+ - spec/schema.rb
82
+ - spec/spec_helper.rb
83
+ homepage: https://github.com/fernandors87/normatron
84
+ licenses: []
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 1.8.24
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Handle normalization for ActiveRecord attributes
107
+ test_files:
108
+ - spec/support/test_model.rb
109
+ - spec/normatron_spec.rb
110
+ - spec/schema.rb
111
+ - spec/spec_helper.rb