normatron 0.0.3 → 0.0.4

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.
@@ -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