vacuum_cleaner 0.1.0
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.
- data/.gitignore +3 -0
- data/LICENSE +20 -0
- data/README.md +6 -0
- data/Rakefile +88 -0
- data/init.rb +4 -0
- data/lib/vacuum_cleaner.rb +6 -0
- data/lib/vacuum_cleaner/normalizations.rb +69 -0
- data/lib/vacuum_cleaner/normalizations/method.rb +48 -0
- data/lib/vacuum_cleaner/normalizations/url.rb +15 -0
- data/lib/vacuum_cleaner/normalizer.rb +67 -0
- data/rails/init.rb +4 -0
- data/test/test_helper.rb +10 -0
- data/test/unit/vacuum_cleaner/normalizations/method_test.rb +33 -0
- data/test/unit/vacuum_cleaner/normalizations/url_test.rb +39 -0
- data/test/unit/vacuum_cleaner/normalizations_test.rb +192 -0
- data/test/unit/vacuum_cleaner/normalizer_test.rb +47 -0
- data/vacuum_cleaner.gemspec +69 -0
- metadata +112 -0
data/.gitignore
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2009 Lukas Westermann
|
|
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.
|
data/README.md
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require 'rake'
|
|
2
|
+
require 'rake/testtask'
|
|
3
|
+
require 'yard'
|
|
4
|
+
require File.join(File.dirname(__FILE__), 'lib', 'vacuum_cleaner')
|
|
5
|
+
|
|
6
|
+
desc 'Test the vacuum_cleaner plugin.'
|
|
7
|
+
Rake::TestTask.new(:test) do |t|
|
|
8
|
+
t.libs << 'lib'
|
|
9
|
+
t.libs << 'test'
|
|
10
|
+
t.pattern = 'test/**/*_test.rb'
|
|
11
|
+
t.verbose = true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
desc 'Generate documentation for vacuum_cleaner. (requires yard)'
|
|
15
|
+
YARD::Rake::YardocTask.new(:doc) do |t|
|
|
16
|
+
t.files = ['lib/**/*.rb']
|
|
17
|
+
t.options = [
|
|
18
|
+
"--readme", "README.md",
|
|
19
|
+
"--title", "vacuum_cleaner (v#{VacuumCleaner::VERSION}) API Documentation"
|
|
20
|
+
]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
begin
|
|
24
|
+
require 'jeweler'
|
|
25
|
+
Jeweler::Tasks.new do |gemspec|
|
|
26
|
+
gemspec.name = "vacuum_cleaner"
|
|
27
|
+
gemspec.version = VacuumCleaner::VERSION
|
|
28
|
+
gemspec.summary = "Ruby (and Rails) attribute cleaning support, provides some nice default normalization strategies."
|
|
29
|
+
description = <<-DESC
|
|
30
|
+
** Swoooosh ** - and all those leading and trailing whitespaces are gone, or ** Frooom ** - and the value
|
|
31
|
+
is normalized to always be prefixed by 'http://' and much more. Works with both plain old Ruby, and Rails (ActiveModel
|
|
32
|
+
and ActiveSupport).
|
|
33
|
+
DESC
|
|
34
|
+
gemspec.description = description.strip
|
|
35
|
+
gemspec.email = "lukas.westermann@gmail.com"
|
|
36
|
+
gemspec.homepage = "http://github.com/lwe/vacuum_cleaner"
|
|
37
|
+
gemspec.authors = ["Lukas Westermann"]
|
|
38
|
+
gemspec.licenses = %w{LICENSE}
|
|
39
|
+
gemspec.extra_rdoc_files = %w{README.md}
|
|
40
|
+
|
|
41
|
+
gemspec.add_development_dependency('shoulda', '>= 2.10.2')
|
|
42
|
+
gemspec.add_development_dependency('rr', '>= 0.10.5')
|
|
43
|
+
# gemspec.add_development_dependency('activesupport', '>= 2.3.5')
|
|
44
|
+
end
|
|
45
|
+
Jeweler::GemcutterTasks.new
|
|
46
|
+
rescue LoadError
|
|
47
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
desc 'Clean all generated files (.yardoc and doc/*)'
|
|
51
|
+
task :clean do |t|
|
|
52
|
+
FileUtils.rm_rf "doc"
|
|
53
|
+
FileUtils.rm_rf "pkg"
|
|
54
|
+
FileUtils.rm_rf ".yardoc"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
namespace :metrics do
|
|
58
|
+
desc 'Report all metrics, i.e. stats and code coverage.'
|
|
59
|
+
task :all => [:stats, :coverage]
|
|
60
|
+
|
|
61
|
+
desc 'Report code statistics for library and tests to shell.'
|
|
62
|
+
task :stats do |t|
|
|
63
|
+
require 'code_statistics'
|
|
64
|
+
dirs = {
|
|
65
|
+
'Libraries' => 'lib',
|
|
66
|
+
'Unit tests' => 'test/unit'
|
|
67
|
+
}.map { |name,dir| [name, File.join(File.dirname(__FILE__), dir)] }
|
|
68
|
+
CodeStatistics.new(*dirs).to_s
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
desc 'Report code coverage to HTML (doc/coverage) and shell (requires rcov).'
|
|
72
|
+
task :coverage do |t|
|
|
73
|
+
rm_f "doc/coverage"
|
|
74
|
+
mkdir_p "doc/coverage"
|
|
75
|
+
rcov = %(rcov -Ilib:test --exclude '\/gems\/' -o doc/coverage -T test/unit/vacuum_cleaner/*_test.rb -T test/unit/vacuum_cleaner/*/*_test.rb)
|
|
76
|
+
system rcov
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
desc 'Report the fishy smell of bad code (requires reek)'
|
|
80
|
+
task :smelly do |t|
|
|
81
|
+
puts
|
|
82
|
+
puts "* * * NOTE: reek currently reports several false positives,"
|
|
83
|
+
puts " eventhough it's probably good to check once in a while!"
|
|
84
|
+
puts
|
|
85
|
+
reek = %(reek -s lib)
|
|
86
|
+
system reek
|
|
87
|
+
end
|
|
88
|
+
end
|
data/init.rb
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module VacuumCleaner
|
|
2
|
+
# Suffix added to existing setter methods
|
|
3
|
+
WITHOUT_NORMALIZATION_SUFFIX = "_without_normalization"
|
|
4
|
+
|
|
5
|
+
module Normalizations
|
|
6
|
+
|
|
7
|
+
def self.included(base)
|
|
8
|
+
base.extend(ClassMethods)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ClassMethods
|
|
12
|
+
def normalizes(*attributes, &block)
|
|
13
|
+
metaklass = class << self; self; end
|
|
14
|
+
|
|
15
|
+
normalizations = attributes.last.is_a?(Hash) ? attributes.pop : {}
|
|
16
|
+
raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
|
|
17
|
+
|
|
18
|
+
normalizers = []
|
|
19
|
+
normalizers << Normalizer.new unless normalizations.delete(:default) === false
|
|
20
|
+
|
|
21
|
+
normalizations.each do |key, options|
|
|
22
|
+
begin
|
|
23
|
+
normalizers << const_get("#{VacuumCleaner.camelize_value(key)}Normalizer").new(options === true ? {} : options)
|
|
24
|
+
rescue NameError
|
|
25
|
+
raise ArgumentError, "Unknown normalizer: '#{key}'"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
attributes.each do |attribute|
|
|
30
|
+
attribute = attribute.to_sym
|
|
31
|
+
send(:define_method, :"normalize_#{attribute}") do |value|
|
|
32
|
+
value = normalizers.inject(value) { |v,n| n.normalize(self, attribute, v) }
|
|
33
|
+
block_given? ? (block.arity == 1 ? yield(value) : yield(self, attribute, value)) : value
|
|
34
|
+
end
|
|
35
|
+
original_setter = "#{attribute}#{VacuumCleaner::WITHOUT_NORMALIZATION_SUFFIX}=".to_sym
|
|
36
|
+
send(:alias_method, original_setter, "#{attribute}=") if instance_methods.include?("#{attribute}=")
|
|
37
|
+
|
|
38
|
+
rb_src = <<-RUBY
|
|
39
|
+
def #{attribute}=(value) # 1. def name=(value)
|
|
40
|
+
value = send(:'normalize_#{attribute}', value) # 2. value = send(:'normalize_name', value)
|
|
41
|
+
return send(#{original_setter.inspect}, value) if respond_to?(#{original_setter.inspect}) # 3. return send(:'name_wo...=', value) if respond_to?(:'name_wo...=')
|
|
42
|
+
return send(:write_attribute, #{attribute.inspect}, value) if respond_to?(:write_attribute) # 4. return send(:write_attribute, :name, value) if respond_to?(:write_attribute)
|
|
43
|
+
@#{attribute} = value # 5. @name = value
|
|
44
|
+
end # 6. end
|
|
45
|
+
RUBY
|
|
46
|
+
|
|
47
|
+
module_eval rb_src, __FILE__, __LINE__
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Okay, because this library currently does not depend on
|
|
54
|
+
# <tt>ActiveSupport</tt> or anything similar an "independent" camelizing process is
|
|
55
|
+
# required. So it works pretty easy.
|
|
56
|
+
#
|
|
57
|
+
# If <tt>value.to_s</tt> responds to <tt>:camelize</tt>, then call it else use implementation
|
|
58
|
+
# taken from http://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L25
|
|
59
|
+
def camelize_value(value)
|
|
60
|
+
value = value.to_s
|
|
61
|
+
value.respond_to?(:camelize) ? value.camelize : value.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
|
62
|
+
end
|
|
63
|
+
module_function :camelize_value
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# load standard normalizations
|
|
67
|
+
Dir[File.dirname(__FILE__) + "/normalizations/*.rb"].sort.each do |path|
|
|
68
|
+
require "vacuum_cleaner/normalizations/#{File.basename(path)}"
|
|
69
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module VacuumCleaner
|
|
2
|
+
module Normalizations
|
|
3
|
+
|
|
4
|
+
# Generic method based normalizer which just calls supplied method
|
|
5
|
+
# on value (unless nil).
|
|
6
|
+
#
|
|
7
|
+
# normalizes :name, :method => :titelize
|
|
8
|
+
#
|
|
9
|
+
# Custom instances accept a <tt>:method</tt> option.
|
|
10
|
+
#
|
|
11
|
+
# MethodNormalizer.new(:method => :titelize)
|
|
12
|
+
#
|
|
13
|
+
# Subclasses of the +MethodNormalizer+ can take advantage of it's
|
|
14
|
+
# +normalize_if_respond_to+ method, to easily create custom
|
|
15
|
+
# normalizers based on methods availble on the result value.
|
|
16
|
+
class MethodNormalizer < Normalizer
|
|
17
|
+
# Ensure access to default normalization method
|
|
18
|
+
alias_method :default_normalize_value, :normalize_value
|
|
19
|
+
|
|
20
|
+
# Helper method to "bake" a method normalizer from a method, enabling us to do stuff like.
|
|
21
|
+
#
|
|
22
|
+
# TitelizeNormalizer = MethodNormalizer.build(:titleize)
|
|
23
|
+
#
|
|
24
|
+
def self.build(sym)
|
|
25
|
+
module_eval "Class.new(MethodNormalizer) do; def initialize(*args); super({ :method => #{sym.inspect}}) end; end", __FILE__, __LINE__
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Accept either a hash or symbol name.
|
|
29
|
+
def initialize(args = {})
|
|
30
|
+
args = { :method => args } unless args.is_a?(Hash)
|
|
31
|
+
super(args)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Normalize value by calling the default normalizer (strip + nil if empty)
|
|
35
|
+
# and then if not <tt>nil</tt> call the method defined.
|
|
36
|
+
def normalize_value(value)
|
|
37
|
+
sym = options[:method]
|
|
38
|
+
value.respond_to?(sym) ? value.send(sym) : value
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Downcase value unless nil or empty.
|
|
43
|
+
DowncaseNormalizer = MethodNormalizer.build(:downcase)
|
|
44
|
+
|
|
45
|
+
# Upcases value unless nil or empty.
|
|
46
|
+
UpcaseNormalizer = MethodNormalizer.build(:upcase)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module VacuumCleaner
|
|
2
|
+
module Normalizations
|
|
3
|
+
class UrlNormalizer < Normalizer
|
|
4
|
+
def initialize(options = {})
|
|
5
|
+
options = { :scheme => "http://", :unless => %r{\Ahttps?://}i } if options.nil? || options.empty?
|
|
6
|
+
options = { :scheme => options, :unless => %r{\A#{options}}i } unless options.is_a?(Hash)
|
|
7
|
+
super(options)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def normalize_value(value)
|
|
11
|
+
value =~ options[:unless] ? value : "#{options[:scheme]}#{value}" unless value.nil?
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module VacuumCleaner #:nodoc:
|
|
2
|
+
|
|
3
|
+
# A small base class for implementing custom value normalizers.
|
|
4
|
+
# Might seem like a slight overkill, yet makes the library pretty
|
|
5
|
+
# reusable and all. Based on Rails 3 validator stuff.
|
|
6
|
+
#
|
|
7
|
+
#
|
|
8
|
+
# class Person
|
|
9
|
+
# include VacuumCleaner::Normalizations
|
|
10
|
+
# normalizes :name, :titleize => true
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# class TitleizeNormalizer < VacuumCleaner::Normalizer
|
|
14
|
+
# def normalize_value(value)
|
|
15
|
+
# value.titelize unless value.blank?
|
|
16
|
+
# end
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# Any class that inherits from +VacuumCleaner::Normalizer+ must implement
|
|
20
|
+
# a method called <tt>normalize_value</tt> which accepts the <tt>value</tt> to normalize. Furthermore
|
|
21
|
+
# the value returned by <tt>normalize</tt> is used as the new value for
|
|
22
|
+
# the attribute.
|
|
23
|
+
#
|
|
24
|
+
# To reuse the behaviour as defined by the default normalizer (strip & empty),
|
|
25
|
+
# just use <tt>super</tt>.
|
|
26
|
+
#
|
|
27
|
+
# class TitleizeNormalizer < VacuumCleaner::Normalizer
|
|
28
|
+
# def normalize_value(value)
|
|
29
|
+
# super(value).try(:titelize)
|
|
30
|
+
# end
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# If access to the record or attribute being normalized is required the method
|
|
34
|
+
# +normalize+ can be overriden instead.
|
|
35
|
+
#
|
|
36
|
+
# class FancyNormalizer < VacuumCleaner::Normalizer
|
|
37
|
+
# def normalize(object, attribute, value)
|
|
38
|
+
# ...
|
|
39
|
+
# end
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# This can be used together with the +normalizes+ method (see
|
|
43
|
+
# VacuumCleaner::Normalizers.normalizes for more on this).
|
|
44
|
+
class Normalizer
|
|
45
|
+
attr_reader :options
|
|
46
|
+
|
|
47
|
+
# Accepts an array of options, which will be made available through the +options+ reader.
|
|
48
|
+
def initialize(options = {})
|
|
49
|
+
@options = options
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Only override this method if access to the <tt>object</tt> or <tt>attribute</tt> name
|
|
53
|
+
# is required, else override +normalize_value+, makes life much simpler :)
|
|
54
|
+
#
|
|
55
|
+
# Default behaviour just calls <tt>normalize_value(value)</tt>.
|
|
56
|
+
def normalize(object, attribute, value); normalize_value(value) end
|
|
57
|
+
|
|
58
|
+
# Override this method in subclasses to specifiy custom normalization steps and magic.
|
|
59
|
+
#
|
|
60
|
+
# The standard implementation strips the value of trailing/leading whitespace and then
|
|
61
|
+
# either returns that value or +nil+ if it's <tt>empty?</tt>.
|
|
62
|
+
def normalize_value(value)
|
|
63
|
+
value = value.strip if value.respond_to?(:strip)
|
|
64
|
+
value.nil? || (value.respond_to?(:empty?) && value.empty?) ? nil : value
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/rails/init.rb
ADDED
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'vacuum_cleaner/normalizer'
|
|
3
|
+
require 'vacuum_cleaner/normalizations/method'
|
|
4
|
+
|
|
5
|
+
class VacuumCleaner::Normalizations::MethodTest < Test::Unit::TestCase
|
|
6
|
+
include VacuumCleaner::Normalizations
|
|
7
|
+
|
|
8
|
+
context "MethodNormalizer" do
|
|
9
|
+
should "accept method name as initialization argument" do
|
|
10
|
+
downcaser = MethodNormalizer.new(:downcase)
|
|
11
|
+
assert_equal "elliot\n", downcaser.normalize_value("Elliot\n")
|
|
12
|
+
assert_equal " \t", downcaser.normalize_value(" \t")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
should "accept hash with :method key as initializer" do
|
|
16
|
+
upcaser = MethodNormalizer.new(:method => :upcase)
|
|
17
|
+
assert_equal "ELLIOT\n", upcaser.normalize_value("Elliot\n")
|
|
18
|
+
assert_equal " \t", upcaser.normalize_value(" \t")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context "DowncaseNormalizer#normalize_value" do
|
|
23
|
+
should "downcase input" do
|
|
24
|
+
assert_equal "elliot", DowncaseNormalizer.new.normalize_value("Elliot")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "UpcaseNormalizer#normalize_value" do
|
|
29
|
+
should "upcase input" do
|
|
30
|
+
assert_equal "J.D.", UpcaseNormalizer.new.normalize_value("j.d.")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'vacuum_cleaner/normalizer'
|
|
3
|
+
require 'vacuum_cleaner/normalizations/url'
|
|
4
|
+
|
|
5
|
+
class VacuumCleaner::Normalizations::UrlTest < Test::Unit::TestCase
|
|
6
|
+
include VacuumCleaner::Normalizations
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# normalizes :homepage, :url => true
|
|
10
|
+
# normalizes :ftp, :url => "ftp://"
|
|
11
|
+
# normalizes :uri, :url => { :scheme => "http://", :unless => %r{\A(https?://|ftp://|jabber:)} }
|
|
12
|
+
#
|
|
13
|
+
context "UrlNormalizer#normalize_value" do
|
|
14
|
+
should "ignore <nil>" do
|
|
15
|
+
assert_nil UrlNormalizer.new.normalize_value(nil)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
should "prefix string with 'http://' if string does not begin with it" do
|
|
19
|
+
assert_equal "http://google.com", UrlNormalizer.new.normalize_value("google.com")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
should "not prefix string with 'http://' if string already begins with http or https" do
|
|
23
|
+
assert_equal "http://google.com/", UrlNormalizer.new.normalize_value("http://google.com/")
|
|
24
|
+
assert_equal "https://docs.google.com/", UrlNormalizer.new.normalize_value("https://docs.google.com/")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
should "allow to specify custom scheme, like ftp://" do
|
|
28
|
+
assert_equal "ftp://ftp.sacred-heart.com", UrlNormalizer.new("ftp://").normalize_value("ftp.sacred-heart.com")
|
|
29
|
+
assert_equal "ftp://ftp.sacred-heart.com", UrlNormalizer.new("ftp://").normalize_value("ftp://ftp.sacred-heart.com")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
should "allow to specify :scheme and custom regex to exclude/allow certain protocols" do
|
|
33
|
+
n = UrlNormalizer.new(:scheme => "http://", :unless => %r{\A(https?://|ftp://|jabber:)})
|
|
34
|
+
assert_equal "http://google.com", n.normalize_value("google.com")
|
|
35
|
+
assert_equal "jabber:jd@sh.com", n.normalize_value("jabber:jd@sh.com")
|
|
36
|
+
assert_equal "https://docs.google.com", n.normalize_value("https://docs.google.com")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
require 'vacuum_cleaner/normalizer'
|
|
4
|
+
require 'vacuum_cleaner/normalizations'
|
|
5
|
+
|
|
6
|
+
class PrefixDoctorNormalizer < VacuumCleaner::Normalizer
|
|
7
|
+
def normalize_value(value)
|
|
8
|
+
"Dr. #{value}"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Person
|
|
13
|
+
include VacuumCleaner::Normalizations
|
|
14
|
+
|
|
15
|
+
attr_accessor :last_name, :first_name
|
|
16
|
+
|
|
17
|
+
normalizes :last_name
|
|
18
|
+
normalizes :first_name
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Doctor
|
|
22
|
+
include VacuumCleaner::Normalizations
|
|
23
|
+
attr_accessor :name
|
|
24
|
+
|
|
25
|
+
class GirlifyNormalizer < VacuumCleaner::Normalizer
|
|
26
|
+
def normalize_value(value)
|
|
27
|
+
value == "J.D." ? "Maria" : value
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
normalizes :name, :girlify => true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class VacuumCleaner::NormalizationsTest < Test::Unit::TestCase
|
|
35
|
+
context "VacuumCleaner::Normalizations" do
|
|
36
|
+
context "ClassMethods#normalizes" do
|
|
37
|
+
should "throw ArgumentError if no attributes are passed in" do
|
|
38
|
+
assert_raise ArgumentError do
|
|
39
|
+
klass = Class.new do
|
|
40
|
+
include VacuumCleaner::Normalizations
|
|
41
|
+
normalizes
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
should "take a symbol as argument" do
|
|
47
|
+
assert_respond_to Class.new { include VacuumCleaner::Normalizations; normalizes(:name) }, :normalizes
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
should "take multiple symbols as argument" do
|
|
51
|
+
klass = Class.new { include VacuumCleaner::Normalizations; normalizes(:name, :first_name) }
|
|
52
|
+
assert_respond_to klass, :normalizes
|
|
53
|
+
#assert_respond_to klass, :normalize_name
|
|
54
|
+
#assert_respond_to klass, :normalize_first_name
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
should "create a setter for supplied attribute" do
|
|
58
|
+
obj = Class.new { include VacuumCleaner::Normalizations; normalizes(:name) }.new
|
|
59
|
+
assert_respond_to obj, :name=
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
should "set the instance variable using the setter" do
|
|
63
|
+
obj = Class.new { include VacuumCleaner::Normalizations; normalizes(:name) }.new
|
|
64
|
+
obj.name = "J.D."
|
|
65
|
+
assert_equal "J.D.", obj.instance_variable_get(:@name)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
should "alias method to <attr>_without_normalization= if <attr>= already defined" do
|
|
69
|
+
klass = Class.new do
|
|
70
|
+
include VacuumCleaner::Normalizations
|
|
71
|
+
def name=(name); @foo = name end
|
|
72
|
+
normalizes :name
|
|
73
|
+
end
|
|
74
|
+
obj = klass.new
|
|
75
|
+
obj.name = "Elliot Reid"
|
|
76
|
+
assert_respond_to obj, :name_without_normalization=
|
|
77
|
+
assert_equal "Elliot Reid", obj.instance_variable_get(:@foo)
|
|
78
|
+
assert_nil obj.instance_variable_get(:@name)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
should "convert any blank input, like empty string, nil etc. to => <nil>" do
|
|
82
|
+
obj = Person.new
|
|
83
|
+
obj.first_name = " "
|
|
84
|
+
obj.last_name = ''
|
|
85
|
+
assert_nil obj.first_name
|
|
86
|
+
assert_nil obj.last_name
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
should "strip leading and trailing white-space" do
|
|
90
|
+
obj = Person.new
|
|
91
|
+
obj.first_name = "\nElliot\t "
|
|
92
|
+
obj.last_name = nil
|
|
93
|
+
assert_nil obj.last_name
|
|
94
|
+
assert_equal "Elliot", obj.first_name
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
should "accept a block which overrides the default to_nil_if_empty strategy" do
|
|
98
|
+
klass = Class.new do
|
|
99
|
+
include VacuumCleaner::Normalizations
|
|
100
|
+
attr_accessor :name
|
|
101
|
+
normalizes :name do |value|
|
|
102
|
+
value ? value.upcase : value
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
obj = klass.new
|
|
106
|
+
obj.name = "Turk"
|
|
107
|
+
assert_equal "TURK", obj.name
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
should "accept custom options hash to define other normalizers to run" do
|
|
111
|
+
klass = Class.new do
|
|
112
|
+
include VacuumCleaner::Normalizations
|
|
113
|
+
attr_accessor :email
|
|
114
|
+
normalizes :email, :downcase => true
|
|
115
|
+
end
|
|
116
|
+
obj = klass.new
|
|
117
|
+
obj.email = "\nJ.D.Dorian@Sacred-Heart.com "
|
|
118
|
+
assert_equal "j.d.dorian@sacred-heart.com", obj.email
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
should "raise ArgumentError if invalid/unknown normalizer is called" do
|
|
122
|
+
assert_raise ArgumentError do
|
|
123
|
+
Class.new do
|
|
124
|
+
include VacuumCleaner::Normalizations
|
|
125
|
+
normalizes :foo, :invalid_unknown_normalizer => true
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
should "ignore default split/empty? normalizer if :default => false" do
|
|
131
|
+
klass = Class.new do
|
|
132
|
+
include VacuumCleaner::Normalizations
|
|
133
|
+
attr_accessor :name
|
|
134
|
+
normalizes :name, :default => false, :upcase => true
|
|
135
|
+
end
|
|
136
|
+
obj = klass.new
|
|
137
|
+
obj.name = "Dr. Dorian\n\t"
|
|
138
|
+
assert_equal "DR. DORIAN\n\t", obj.name
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
should "be able to use normalizers from the global namespace" do
|
|
142
|
+
klass = Class.new do
|
|
143
|
+
include VacuumCleaner::Normalizations
|
|
144
|
+
attr_accessor :name
|
|
145
|
+
normalizes :name, :prefix_doctor => true
|
|
146
|
+
end
|
|
147
|
+
obj = klass.new
|
|
148
|
+
obj.name = "Elliot Reid"
|
|
149
|
+
assert_equal "Dr. Elliot Reid", obj.name
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
should "be able to use normalizers from within the class itself" do
|
|
153
|
+
obj = Doctor.new
|
|
154
|
+
obj.name = "Elliot Reid"
|
|
155
|
+
assert_equal "Elliot Reid", obj.name
|
|
156
|
+
obj = Doctor.new
|
|
157
|
+
obj.name = "J.D."
|
|
158
|
+
assert_equal "Maria", obj.name
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
should "be able to combine normalizers and custom blocks" do
|
|
162
|
+
klass = Class.new do
|
|
163
|
+
include VacuumCleaner::Normalizations
|
|
164
|
+
attr_accessor :name, :first_name
|
|
165
|
+
normalizes(:name, :first_name, :downcase => true) do |value|
|
|
166
|
+
value.nil? ? value : "#{value.to_s[0,1].upcase}#{value.to_s[1..-1]}"
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
obj = klass.new
|
|
171
|
+
obj.name = "REID"
|
|
172
|
+
obj.first_name = "ELLIOT"
|
|
173
|
+
assert_equal "Reid", obj.name
|
|
174
|
+
assert_equal "Elliot", obj.first_name
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
should "provide block with all values if asking for them!" do
|
|
178
|
+
klass = Class.new do
|
|
179
|
+
include VacuumCleaner::Normalizations
|
|
180
|
+
attr_accessor :name
|
|
181
|
+
normalizes(:name) do |object, attribute, value|
|
|
182
|
+
[object.object_id, attribute, value]
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
obj = klass.new
|
|
187
|
+
obj.name = "Carla"
|
|
188
|
+
assert_equal [obj.object_id, :name, "Carla"], obj.name
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'vacuum_cleaner/normalizer'
|
|
3
|
+
|
|
4
|
+
class VacuumCleaner::NormalizerTest < Test::Unit::TestCase
|
|
5
|
+
context "VacuumCleaner::Normalizer" do
|
|
6
|
+
should "take an optional hash as argument during #initialize and expose that hash when calling #options" do
|
|
7
|
+
expected = { :doctor => "Dr. Dorian", :nurse => "Carla" }
|
|
8
|
+
normalizer = VacuumCleaner::Normalizer.new({ :doctor => "Dr. Dorian", :nurse => "Carla" })
|
|
9
|
+
assert_equal "Dr. Dorian", normalizer.options[:doctor]
|
|
10
|
+
assert_equal expected, normalizer.options
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context "#normalize_value" do
|
|
14
|
+
should "leave <nil>" do
|
|
15
|
+
assert_nil VacuumCleaner::Normalizer.new.normalize_value(nil)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
should "convert empty string to <nil>" do
|
|
19
|
+
assert_nil VacuumCleaner::Normalizer.new.normalize_value('')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
should "convert string with only space characters to <nil>" do
|
|
23
|
+
assert_nil VacuumCleaner::Normalizer.new.normalize_value(" ")
|
|
24
|
+
assert_nil VacuumCleaner::Normalizer.new.normalize_value(" \n\t ")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
should "strip leading and trailing whitespace" do
|
|
28
|
+
assert_equal "Dr. Reid", VacuumCleaner::Normalizer.new.normalize_value(" \nDr. Reid\t ")
|
|
29
|
+
assert_equal "Dr. Dorian", VacuumCleaner::Normalizer.new.normalize_value("Dr. Dorian\t \r")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context "#normalize" do
|
|
34
|
+
should "return always the same as #normalize_value and ignore object and attribute parameters" do
|
|
35
|
+
normalizer = VacuumCleaner::Normalizer.new
|
|
36
|
+
object = Object.new
|
|
37
|
+
attribute = :name
|
|
38
|
+
|
|
39
|
+
[["Dr. Reid", "\t Dr. Reid"], ["Dr. Dorian", "Dr. Dorian\n "], [nil, nil], [nil, "\n "], [nil, ""]].each do |tests|
|
|
40
|
+
expected, value = *tests
|
|
41
|
+
assert_equal expected, normalizer.normalize_value(value)
|
|
42
|
+
assert_equal expected, normalizer.normalize(object, attribute, value)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Generated by jeweler
|
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
|
4
|
+
# -*- encoding: utf-8 -*-
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |s|
|
|
7
|
+
s.name = %q{vacuum_cleaner}
|
|
8
|
+
s.version = "0.1.0"
|
|
9
|
+
|
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
|
+
s.authors = ["Lukas Westermann"]
|
|
12
|
+
s.date = %q{2010-02-24}
|
|
13
|
+
s.description = %q{** Swoooosh ** - and all those leading and trailing whitespaces are gone, or ** Frooom ** - and the value
|
|
14
|
+
is normalized to always be prefixed by 'http://' and much more. Works with both plain old Ruby, and Rails (ActiveModel
|
|
15
|
+
and ActiveSupport).}
|
|
16
|
+
s.email = %q{lukas.westermann@gmail.com}
|
|
17
|
+
s.extra_rdoc_files = [
|
|
18
|
+
"README.md"
|
|
19
|
+
]
|
|
20
|
+
s.files = [
|
|
21
|
+
".gitignore",
|
|
22
|
+
"LICENSE",
|
|
23
|
+
"README.md",
|
|
24
|
+
"Rakefile",
|
|
25
|
+
"init.rb",
|
|
26
|
+
"lib/vacuum_cleaner.rb",
|
|
27
|
+
"lib/vacuum_cleaner/normalizations.rb",
|
|
28
|
+
"lib/vacuum_cleaner/normalizations/method.rb",
|
|
29
|
+
"lib/vacuum_cleaner/normalizations/url.rb",
|
|
30
|
+
"lib/vacuum_cleaner/normalizer.rb",
|
|
31
|
+
"rails/init.rb",
|
|
32
|
+
"test/test_helper.rb",
|
|
33
|
+
"test/unit/vacuum_cleaner/normalizations/method_test.rb",
|
|
34
|
+
"test/unit/vacuum_cleaner/normalizations/url_test.rb",
|
|
35
|
+
"test/unit/vacuum_cleaner/normalizations_test.rb",
|
|
36
|
+
"test/unit/vacuum_cleaner/normalizer_test.rb",
|
|
37
|
+
"vacuum_cleaner.gemspec"
|
|
38
|
+
]
|
|
39
|
+
s.homepage = %q{http://github.com/lwe/vacuum_cleaner}
|
|
40
|
+
s.licenses = ["LICENSE"]
|
|
41
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
|
42
|
+
s.require_paths = ["lib"]
|
|
43
|
+
s.rubygems_version = %q{1.3.6}
|
|
44
|
+
s.summary = %q{Ruby (and Rails) attribute cleaning support, provides some nice default normalization strategies.}
|
|
45
|
+
s.test_files = [
|
|
46
|
+
"test/test_helper.rb",
|
|
47
|
+
"test/unit/vacuum_cleaner/normalizations/method_test.rb",
|
|
48
|
+
"test/unit/vacuum_cleaner/normalizations/url_test.rb",
|
|
49
|
+
"test/unit/vacuum_cleaner/normalizations_test.rb",
|
|
50
|
+
"test/unit/vacuum_cleaner/normalizer_test.rb"
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
if s.respond_to? :specification_version then
|
|
54
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
55
|
+
s.specification_version = 3
|
|
56
|
+
|
|
57
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
58
|
+
s.add_development_dependency(%q<shoulda>, [">= 2.10.2"])
|
|
59
|
+
s.add_development_dependency(%q<rr>, [">= 0.10.5"])
|
|
60
|
+
else
|
|
61
|
+
s.add_dependency(%q<shoulda>, [">= 2.10.2"])
|
|
62
|
+
s.add_dependency(%q<rr>, [">= 0.10.5"])
|
|
63
|
+
end
|
|
64
|
+
else
|
|
65
|
+
s.add_dependency(%q<shoulda>, [">= 2.10.2"])
|
|
66
|
+
s.add_dependency(%q<rr>, [">= 0.10.5"])
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
metadata
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: vacuum_cleaner
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease: false
|
|
5
|
+
segments:
|
|
6
|
+
- 0
|
|
7
|
+
- 1
|
|
8
|
+
- 0
|
|
9
|
+
version: 0.1.0
|
|
10
|
+
platform: ruby
|
|
11
|
+
authors:
|
|
12
|
+
- Lukas Westermann
|
|
13
|
+
autorequire:
|
|
14
|
+
bindir: bin
|
|
15
|
+
cert_chain: []
|
|
16
|
+
|
|
17
|
+
date: 2010-02-24 00:00:00 +01:00
|
|
18
|
+
default_executable:
|
|
19
|
+
dependencies:
|
|
20
|
+
- !ruby/object:Gem::Dependency
|
|
21
|
+
name: shoulda
|
|
22
|
+
prerelease: false
|
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
24
|
+
requirements:
|
|
25
|
+
- - ">="
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
segments:
|
|
28
|
+
- 2
|
|
29
|
+
- 10
|
|
30
|
+
- 2
|
|
31
|
+
version: 2.10.2
|
|
32
|
+
type: :development
|
|
33
|
+
version_requirements: *id001
|
|
34
|
+
- !ruby/object:Gem::Dependency
|
|
35
|
+
name: rr
|
|
36
|
+
prerelease: false
|
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
38
|
+
requirements:
|
|
39
|
+
- - ">="
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
segments:
|
|
42
|
+
- 0
|
|
43
|
+
- 10
|
|
44
|
+
- 5
|
|
45
|
+
version: 0.10.5
|
|
46
|
+
type: :development
|
|
47
|
+
version_requirements: *id002
|
|
48
|
+
description: |-
|
|
49
|
+
** Swoooosh ** - and all those leading and trailing whitespaces are gone, or ** Frooom ** - and the value
|
|
50
|
+
is normalized to always be prefixed by 'http://' and much more. Works with both plain old Ruby, and Rails (ActiveModel
|
|
51
|
+
and ActiveSupport).
|
|
52
|
+
email: lukas.westermann@gmail.com
|
|
53
|
+
executables: []
|
|
54
|
+
|
|
55
|
+
extensions: []
|
|
56
|
+
|
|
57
|
+
extra_rdoc_files:
|
|
58
|
+
- README.md
|
|
59
|
+
files:
|
|
60
|
+
- .gitignore
|
|
61
|
+
- LICENSE
|
|
62
|
+
- README.md
|
|
63
|
+
- Rakefile
|
|
64
|
+
- init.rb
|
|
65
|
+
- lib/vacuum_cleaner.rb
|
|
66
|
+
- lib/vacuum_cleaner/normalizations.rb
|
|
67
|
+
- lib/vacuum_cleaner/normalizations/method.rb
|
|
68
|
+
- lib/vacuum_cleaner/normalizations/url.rb
|
|
69
|
+
- lib/vacuum_cleaner/normalizer.rb
|
|
70
|
+
- rails/init.rb
|
|
71
|
+
- test/test_helper.rb
|
|
72
|
+
- test/unit/vacuum_cleaner/normalizations/method_test.rb
|
|
73
|
+
- test/unit/vacuum_cleaner/normalizations/url_test.rb
|
|
74
|
+
- test/unit/vacuum_cleaner/normalizations_test.rb
|
|
75
|
+
- test/unit/vacuum_cleaner/normalizer_test.rb
|
|
76
|
+
- vacuum_cleaner.gemspec
|
|
77
|
+
has_rdoc: true
|
|
78
|
+
homepage: http://github.com/lwe/vacuum_cleaner
|
|
79
|
+
licenses:
|
|
80
|
+
- LICENSE
|
|
81
|
+
post_install_message:
|
|
82
|
+
rdoc_options:
|
|
83
|
+
- --charset=UTF-8
|
|
84
|
+
require_paths:
|
|
85
|
+
- lib
|
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - ">="
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
segments:
|
|
91
|
+
- 0
|
|
92
|
+
version: "0"
|
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - ">="
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
segments:
|
|
98
|
+
- 0
|
|
99
|
+
version: "0"
|
|
100
|
+
requirements: []
|
|
101
|
+
|
|
102
|
+
rubyforge_project:
|
|
103
|
+
rubygems_version: 1.3.6
|
|
104
|
+
signing_key:
|
|
105
|
+
specification_version: 3
|
|
106
|
+
summary: Ruby (and Rails) attribute cleaning support, provides some nice default normalization strategies.
|
|
107
|
+
test_files:
|
|
108
|
+
- test/test_helper.rb
|
|
109
|
+
- test/unit/vacuum_cleaner/normalizations/method_test.rb
|
|
110
|
+
- test/unit/vacuum_cleaner/normalizations/url_test.rb
|
|
111
|
+
- test/unit/vacuum_cleaner/normalizations_test.rb
|
|
112
|
+
- test/unit/vacuum_cleaner/normalizer_test.rb
|