normatron 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,31 @@
1
1
  = Normatron
2
2
 
3
- This project rocks and uses MIT-LICENSE.
3
+ Normatron is a attribute normalizer for ActiveRecord.
4
+
5
+ = Installation
6
+
7
+ Add the following into your gemfile:
8
+
9
+ gem 'normatron'
10
+
11
+ Bundle it up:
12
+
13
+ $ bundle install
14
+
15
+ = Usage
16
+
17
+ Let's take an example model:
18
+
19
+ app/models/product.rb
20
+ class Product < ActiveRecord::Base
21
+ attr_accessible :name
22
+
23
+ normalize :name, :with => :upcase
24
+ end
25
+
26
+ $ rails console
27
+ > p = Product.new
28
+ > p.name = " memory card "
29
+ > p.valid?
30
+ > p.name
31
+ => " MEMORY CARD "
@@ -2,7 +2,6 @@ require "active_record"
2
2
 
3
3
  module Normatron
4
4
  module ActiveRecord
5
- include Conversors
6
5
 
7
6
  def self.included(base)
8
7
  base.instance_eval do
@@ -11,39 +10,63 @@ module Normatron
11
10
  before_validation :normalize_attributes
12
11
 
13
12
  class << self
14
- attr_accessor :standardize_options
13
+ attr_accessor :normalization_options
15
14
  end
16
15
  end
17
16
  end
18
17
 
19
18
  module ClassMethods
19
+ # Set an attribute normalization before model validation.
20
+ # Args uses the attribute names following by a hash with conversion options.
21
+ #
22
+ # Example 1:
23
+ # normalize :attribute_name
24
+ #
25
+ # Example 2:
26
+ # normalize :attribute_name, :with => :upcase
27
+ #
28
+ # Example 3:
29
+ # normalize :attribute_name, :with => [:squish, :downcase]
20
30
  def normalize(*args)
21
31
  # Extract options
22
- self.standardize_options ||= {}
32
+ @normalization_options ||= {}
23
33
  options = args.extract_options!
24
34
 
25
- methods = []
35
+ # Set conversors
36
+ conversors = []
26
37
  if options.empty? # Default standardization
27
- methods << [:trim, :strip, :nillify]
38
+ conversors << [:squish, :strip, :nillify]
28
39
  elsif options.has_key? :with
29
- methods << options[:with]
40
+ conversors << options[:with]
30
41
  else
31
- raise "Wrong normalization option in #{self.name}, use :with instead."
42
+ raise "Wrong normalization key in #{self.name}, use :with instead of #{options.keys.first}"
32
43
  end
33
44
 
34
45
  # Make a prettier array
35
- methods = methods.flatten.compact
36
- methods.map! { |v| v = v.to_sym }
46
+ conversors = conversors.flatten.compact
47
+ conversors.map! { |v| v = v.to_sym }
37
48
 
38
- # Add normalization methods to call
49
+ # Check conversors
50
+ conversors.each do |c|
51
+ unless Conversors::CALLBACKS.include? c
52
+ raise "Normalization callback '#{c}' doesn't exist"
53
+ end
54
+ end
55
+
56
+ # Add normalization conversors
39
57
  args.each do |attribute|
40
- standardize_options[attribute] = methods
58
+ # Check attributes
59
+ unless self.column_names.include? attribute.to_s
60
+ raise "Attribute '#{attribute}' doesn't exist in #{self.name}"
61
+ end
62
+
63
+ @normalization_options[attribute] = conversors
41
64
  end
42
65
  end
43
66
  end
44
67
 
45
68
  def normalize_attributes
46
- options = self.class.standardize_options
69
+ options = self.class.normalization_options
47
70
  return unless options
48
71
 
49
72
  options.each do |attribute, methods|
@@ -51,7 +74,8 @@ module Normatron
51
74
 
52
75
  methods.each do |method|
53
76
  # Skip if value is nil originally or the method 'nullify' was called before
54
- value = convert(method, value) unless value.nil?
77
+ value = Conversors.convert(method, value) unless value.nil?
78
+
55
79
  if value == :no_method
56
80
  raise ArgumentError, "Method :#{method} cannot be resolved.
57
81
  Check options for #{attribute} in #{klass}", caller
@@ -4,46 +4,47 @@ require "active_support/all"
4
4
  module Normatron
5
5
  module Conversors
6
6
 
7
- @@MB_CHARS_METHODS = [:upcase, :downcase, :capitalize, :lstrip, :rstrip, :strip, :titlecase, :titleize]
8
- @@SELF_METHODS = [:nillify, :nullify, :nil, :squish, :currency, :integer, :float, :postal_code, :phone, :digits, :phrase]
7
+ MB_CHARS_METHODS = [:upcase, :downcase, :capitalize, :lstrip, :rstrip, :strip, :titlecase, :titleize]
8
+ SELF_METHODS = [:nillify, :nullify, :nil, :squish, :currency, :integer, :float, :postal_code, :phone, :digits, :phrase]
9
+ CALLBACKS = MB_CHARS_METHODS + SELF_METHODS
9
10
 
10
- def convert(method, value)
11
- if @@MB_CHARS_METHODS.include? method
11
+ def self.convert(method, value)
12
+ if MB_CHARS_METHODS.include? method
12
13
  value.mb_chars.send(method).to_s
13
- elsif @@SELF_METHODS.include? method
14
+ elsif SELF_METHODS.include? method
14
15
  send("convert_#{method}", value)
15
16
  else
16
17
  :no_method
17
18
  end
18
19
  end
19
20
 
20
- private
21
-
22
21
  # Return nil if value is blank or else value itself.
23
- def convert_nillify(value)
22
+ def self.convert_nillify(value)
24
23
  value.blank? ? nil : value
25
24
  end
26
- alias :convert_nil :convert_nillify
27
- alias :convert_nullify :convert_nillify
25
+ class << self
26
+ alias :convert_nil :convert_nillify
27
+ alias :convert_nullify :convert_nillify
28
+ end
28
29
 
29
30
  # Remove repeated spaces from the string.
30
- def convert_squish(value)
31
+ def self.convert_squish(value)
31
32
  value.mb_chars.to_s.gsub(/\p{Zs}+/u, ' ')
32
33
  end
33
34
 
34
- def convert_currency(value)
35
+ def self.convert_currency(value)
35
36
  convert_number value, :currency
36
37
  end
37
38
 
38
- def convert_float(value)
39
+ def self.convert_float(value)
39
40
  convert_number value, :float
40
41
  end
41
42
 
42
- def convert_integer(value)
43
+ def self.convert_integer(value)
43
44
  convert_number value
44
45
  end
45
46
 
46
- def convert_number(value, type = :integer)
47
+ def self.convert_number(value, type = :integer)
47
48
  return value unless value.is_a?(String) && value.present?
48
49
 
49
50
  # Find the first number in the sequence
@@ -70,21 +71,21 @@ module Normatron
70
71
  res
71
72
  end
72
73
 
73
- def convert_postal_code(value)
74
+ def self.convert_postal_code(value)
74
75
  res = convert_digits value
75
76
  res.size == 8 ? "%s-%s" % [res[0..4], res[5..7]] : value
76
77
  end
77
78
 
78
- def convert_phone(value)
79
+ def self.convert_phone(value)
79
80
  res = convert_digits value
80
81
  res.size == 10 ? "(%s) %s-%s" % [res[0..1], res[2..5], res[6..9]] : value
81
82
  end
82
83
 
83
- def convert_digits(value)
84
+ def self.convert_digits(value)
84
85
  value.to_s.gsub(/[^\d]/, '')
85
86
  end
86
87
 
87
- def convert_phrase(value)
88
+ def self.convert_phrase(value)
88
89
  convert(:squish, convert(:strip, value))
89
90
  end
90
91
  end
@@ -1,3 +1,3 @@
1
1
  module Normatron
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -4,119 +4,145 @@ require "spec_helper"
4
4
 
5
5
  describe Normatron do
6
6
  before :each do
7
- TestModel.standardize_options = nil
7
+ TestModel.normalization_options = nil
8
+ @instance = TestModel.new
8
9
  end
9
10
 
10
- it "should save without any normalize options" do
11
+ it "should allow save without any normalize option" do
11
12
  lambda do
12
- a = TestModel.new
13
- a.string_field = "a"
14
- a.save!
13
+ @instance.string_column = "Any string"
14
+ @instance.save!
15
15
  end.should_not raise_error
16
16
  end
17
17
 
18
+ it "should raise an error if attribute doesn't exist" do
19
+ lambda do
20
+ TestModel.normalize :ghost_attribute
21
+ end.should raise_error "Attribute 'ghost_attribute' doesn't exist in TestModel"
22
+ end
23
+
24
+ it "should raise an error if a wrong option is set" do
25
+ lambda do
26
+ TestModel.normalize :string_column, :wrong_option => :upcase
27
+ end.should raise_error "Wrong normalization key in TestModel, use :with instead of wrong_option"
28
+ end
29
+
30
+ it "should raise an error if wrong conversor is called" do
31
+ lambda do
32
+ TestModel.normalize :string_column, :with => :wrong_conversor
33
+ end.should raise_error "Normalization callback 'wrong_conversor' doesn't exist"
34
+ end
35
+
36
+ it "options should be accessible" do
37
+ TestModel.normalize :string_column, :with => [:capitalize, :upcase]
38
+ TestModel.normalize :integer_column, :with => :integer
39
+ TestModel.normalization_options.should == { :string_column => [:capitalize, :upcase], :integer_column => [:integer] }
40
+ TestModel.normalization_options.delete :string_column
41
+ TestModel.normalization_options.should == { :integer_column => [:integer] }
42
+ end
43
+
18
44
  describe "Conversors" do
19
45
  it :capitalize do
20
- TestModel.normalize :string_field, :with => :capitalize
46
+ TestModel.normalize :string_column, :with => :capitalize
21
47
 
22
- m = TestModel.create :string_field => "áb c, 1 2 3 DEF GHI i oz "
23
- m.string_field.should == "Áb c, 1 2 3 def ghi i oz "
48
+ m = TestModel.create :string_column => "áb c, 1 2 3 DEF GHI i oz "
49
+ m.string_column.should == "Áb c, 1 2 3 def ghi i oz "
24
50
  end
25
51
 
26
52
  it :digits do
27
- TestModel.normalize :string_field, :with => :digits
53
+ TestModel.normalize :string_column, :with => :digits
28
54
 
29
- m = TestModel.create :string_field => " 1a 2b 3c 4d 5e 6f "
30
- m.string_field.should == "123456"
55
+ m = TestModel.create :string_column => " 1a 2b 3c 4d 5e 6f "
56
+ m.string_column.should == "123456"
31
57
  end
32
58
 
33
59
  it :downcase do
34
- TestModel.normalize :string_field, :with => :downcase
60
+ TestModel.normalize :string_column, :with => :downcase
35
61
 
36
- m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
37
- m.string_field.should == " a b c, 1 2 3 def ghi i oz "
62
+ m = TestModel.create :string_column => " a b c, 1 2 3 DEF GHI i oz "
63
+ m.string_column.should == " a b c, 1 2 3 def ghi i oz "
38
64
  end
39
65
 
40
66
  it :phone do
41
- TestModel.normalize :string_field, :with => :phone
67
+ TestModel.normalize :string_column, :with => :phone
42
68
 
43
- m = TestModel.create :string_field => "(99) 9999-9999"
44
- m.string_field.should == "(99) 9999-9999"
69
+ m = TestModel.create :string_column => "(99) 9999-9999"
70
+ m.string_column.should == "(99) 9999-9999"
45
71
 
46
- m = TestModel.create :string_field => "9999999999"
47
- m.string_field.should == "(99) 9999-9999"
72
+ m = TestModel.create :string_column => "9999999999"
73
+ m.string_column.should == "(99) 9999-9999"
48
74
 
49
- m = TestModel.create :string_field => "999999999"
50
- m.string_field.should == "999999999"
75
+ m = TestModel.create :string_column => "999999999"
76
+ m.string_column.should == "999999999"
51
77
  end
52
78
 
53
79
  it :phrase do
54
- TestModel.normalize :string_field, :with => :phrase
80
+ TestModel.normalize :string_column, :with => :phrase
55
81
 
56
- m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
57
- m.string_field.should == "a b c, 1 2 3 DEF GHI i oz"
82
+ m = TestModel.create :string_column => " a b c, 1 2 3 DEF GHI i oz "
83
+ m.string_column.should == "a b c, 1 2 3 DEF GHI i oz"
58
84
  end
59
85
 
60
86
  it :postal_code do
61
- TestModel.normalize :string_field, :with => :postal_code
87
+ TestModel.normalize :string_column, :with => :postal_code
62
88
 
63
- m = TestModel.create :string_field => "88888-888"
64
- m.string_field.should == "88888-888"
89
+ m = TestModel.create :string_column => "88888-888"
90
+ m.string_column.should == "88888-888"
65
91
 
66
- m = TestModel.create :string_field => "88888888"
67
- m.string_field.should == "88888-888"
92
+ m = TestModel.create :string_column => "88888888"
93
+ m.string_column.should == "88888-888"
68
94
 
69
- m = TestModel.create :string_field => "8888888"
70
- m.string_field.should == "8888888"
95
+ m = TestModel.create :string_column => "8888888"
96
+ m.string_column.should == "8888888"
71
97
  end
72
98
 
73
99
  it :squish do
74
- TestModel.normalize :string_field, :with => :squish
100
+ TestModel.normalize :string_column, :with => :squish
75
101
 
76
- m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
77
- m.string_field.should == " a b c, 1 2 3 DEF GHI i oz "
102
+ m = TestModel.create :string_column => " a b c, 1 2 3 DEF GHI i oz "
103
+ m.string_column.should == " a b c, 1 2 3 DEF GHI i oz "
78
104
  end
79
105
 
80
106
  it :strip do
81
- TestModel.normalize :string_field, :with => :strip
107
+ TestModel.normalize :string_column, :with => :strip
82
108
 
83
- m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
84
- m.string_field.should == "a b c, 1 2 3 DEF GHI i oz"
109
+ m = TestModel.create :string_column => " a b c, 1 2 3 DEF GHI i oz "
110
+ m.string_column.should == "a b c, 1 2 3 DEF GHI i oz"
85
111
  end
86
112
 
87
113
  it :titlecase do
88
- TestModel.normalize :string_field, :with => :titlecase
114
+ TestModel.normalize :string_column, :with => :titlecase
89
115
 
90
- m = TestModel.create :string_field => " áb c, 1 2 3 DEF GHI i oz "
91
- m.string_field.should == " Áb C, 1 2 3 Def Ghi I Oz "
116
+ m = TestModel.create :string_column => " áb c, 1 2 3 DEF GHI i oz "
117
+ m.string_column.should == " Áb C, 1 2 3 Def Ghi I Oz "
92
118
  end
93
119
 
94
120
  it :upcase do
95
- TestModel.normalize :string_field, :with => :upcase
121
+ TestModel.normalize :string_column, :with => :upcase
96
122
 
97
- m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
98
- m.string_field.should == " A B C, 1 2 3 DEF GHI I OZ "
123
+ m = TestModel.create :string_column => " a b c, 1 2 3 DEF GHI i oz "
124
+ m.string_column.should == " A B C, 1 2 3 DEF GHI I OZ "
99
125
  end
100
126
 
101
127
  it :nillify do
102
- TestModel.normalize :string_field, :with => :nillify
128
+ TestModel.normalize :string_column, :with => :nillify
103
129
 
104
- m = TestModel.create :string_field => " "
105
- m.string_field.should == nil
130
+ m = TestModel.create :string_column => " "
131
+ m.string_column.should == nil
106
132
  end
107
133
 
108
134
  it :lstrip do
109
- TestModel.normalize :string_field, :with => :lstrip
135
+ TestModel.normalize :string_column, :with => :lstrip
110
136
 
111
- m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
112
- m.string_field.should == "a b c, 1 2 3 DEF GHI i oz "
137
+ m = TestModel.create :string_column => " a b c, 1 2 3 DEF GHI i oz "
138
+ m.string_column.should == "a b c, 1 2 3 DEF GHI i oz "
113
139
  end
114
140
 
115
141
  it :rstrip do
116
- TestModel.normalize :string_field, :with => :rstrip
142
+ TestModel.normalize :string_column, :with => :rstrip
117
143
 
118
- m = TestModel.create :string_field => " a b c, 1 2 3 DEF GHI i oz "
119
- m.string_field.should == " a b c, 1 2 3 DEF GHI i oz"
144
+ m = TestModel.create :string_column => " a b c, 1 2 3 DEF GHI i oz "
145
+ m.string_column.should == " a b c, 1 2 3 DEF GHI i oz"
120
146
  end
121
147
  end
122
148
  end
@@ -1,6 +1,6 @@
1
1
  ActiveRecord::Schema.define(:version => 0) do
2
2
  create_table :test_models do |t|
3
- t.string :string_field
4
- t.integer :integer_field
3
+ t.string :string_column
4
+ t.integer :integer_column
5
5
  end
6
6
  end
@@ -1,3 +1,3 @@
1
1
  class TestModel < ActiveRecord::Base
2
- attr_accessible :string_field, :integer_field
2
+ attr_accessible :string_column, :integer_column
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: normatron
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-22 00:00:00.000000000 Z
12
+ date: 2012-08-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -71,7 +71,6 @@ files:
71
71
  - lib/normatron/active_record.rb
72
72
  - lib/normatron/conversors.rb
73
73
  - lib/normatron/version.rb
74
- - lib/tasks/normatron_tasks.rake
75
74
  - lib/normatron.rb
76
75
  - MIT-LICENSE
77
76
  - Rakefile
@@ -1,4 +0,0 @@
1
- # desc "Explaining what the task does"
2
- # task :normatron do
3
- # # Task goes here
4
- # end