vacuum_cleaner 0.5.0 → 1.0.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/Rakefile +19 -11
- data/init.rb +1 -1
- data/lib/vacuum_cleaner.rb +7 -3
- data/lib/vacuum_cleaner/normalizations.rb +28 -2
- data/lib/vacuum_cleaner/normalizations/method.rb +4 -7
- data/lib/vacuum_cleaner/normalizations/url.rb +22 -1
- data/lib/vacuum_cleaner/normalizer.rb +3 -3
- data/rails/init.rb +1 -2
- data/test/integration/active_record_integration_test.rb +67 -0
- data/test/test_helper.rb +0 -7
- data/test/unit/vacuum_cleaner/normalizations/method_test.rb +5 -0
- data/test/unit/vacuum_cleaner/normalizations/url_test.rb +9 -0
- metadata +7 -19
data/Rakefile
CHANGED
|
@@ -3,22 +3,13 @@ require 'rake/testtask'
|
|
|
3
3
|
|
|
4
4
|
require File.join(File.dirname(__FILE__), 'lib', 'vacuum_cleaner')
|
|
5
5
|
|
|
6
|
-
task :default => :test
|
|
7
|
-
|
|
8
|
-
desc 'Test the vacuum_cleaner plugin.'
|
|
9
|
-
Rake::TestTask.new(:test) do |t|
|
|
10
|
-
t.libs << 'lib'
|
|
11
|
-
t.libs << 'test'
|
|
12
|
-
t.pattern = 'test/**/*_test.rb'
|
|
13
|
-
t.verbose = true
|
|
14
|
-
end
|
|
15
|
-
|
|
16
6
|
begin
|
|
17
7
|
require 'yard'
|
|
18
8
|
desc 'Generate documentation for vacuum_cleaner. (requires yard)'
|
|
19
9
|
YARD::Rake::YardocTask.new(:doc) do |t|
|
|
20
10
|
t.files = ['lib/**/*.rb']
|
|
21
11
|
t.options = [
|
|
12
|
+
"--no-private",
|
|
22
13
|
"--readme", "README.md",
|
|
23
14
|
"--title", "vacuum_cleaner (v#{VacuumCleaner::VERSION}) API Documentation"
|
|
24
15
|
]
|
|
@@ -42,7 +33,6 @@ begin
|
|
|
42
33
|
gemspec.extra_rdoc_files = %w{README.md}
|
|
43
34
|
|
|
44
35
|
gemspec.add_development_dependency('shoulda', '>= 2.10.2')
|
|
45
|
-
gemspec.add_development_dependency('rr', '>= 0.10.5')
|
|
46
36
|
gemspec.add_development_dependency('activesupport', '>= 2.3.5')
|
|
47
37
|
|
|
48
38
|
gemspec.files.reject! { |file| file =~ /\.gemspec$/ } # kinda redundant
|
|
@@ -59,6 +49,24 @@ task :clean do |t|
|
|
|
59
49
|
FileUtils.rm_rf ".yardoc"
|
|
60
50
|
end
|
|
61
51
|
|
|
52
|
+
namespace :test do
|
|
53
|
+
desc 'Test the vacuum_cleaner plugin.'
|
|
54
|
+
Rake::TestTask.new(:unit) do |t|
|
|
55
|
+
t.libs << 'test'
|
|
56
|
+
t.pattern = 'test/unit/**/*_test.rb'
|
|
57
|
+
t.verbose = true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
desc 'Run integration tests for the vacuum_cleaner plugin.'
|
|
61
|
+
Rake::TestTask.new(:integration) do |t|
|
|
62
|
+
t.libs << 'test'
|
|
63
|
+
t.pattern = 'test/integration/**/*_test.rb'
|
|
64
|
+
t.verbose = true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
task :all => [:'test:unit', :'test:integration']
|
|
68
|
+
end
|
|
69
|
+
|
|
62
70
|
namespace :metrics do
|
|
63
71
|
desc 'Report all metrics, i.e. stats and code coverage.'
|
|
64
72
|
task :all => [:stats, :coverage]
|
data/init.rb
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'rails', 'init')
|
data/lib/vacuum_cleaner.rb
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
# Fancy value normalization utility for ruby (and rails)
|
|
1
|
+
# Fancy value normalization utility for ruby (and rails),
|
|
2
|
+
# see {VacuumCleaner::Normalizations} for more information about usage.
|
|
3
|
+
#
|
|
4
|
+
# @see VacuumCleaner::Normalizations
|
|
5
|
+
# @see VacuumCleaner::Normalizer
|
|
2
6
|
module VacuumCleaner
|
|
3
|
-
# +VacuumCleaner+ version
|
|
4
|
-
VERSION = "0.
|
|
7
|
+
# +VacuumCleaner+ version
|
|
8
|
+
VERSION = "1.0.0".freeze
|
|
5
9
|
|
|
6
10
|
autoload :Normalizer, 'vacuum_cleaner/normalizer'
|
|
7
11
|
autoload :Normalizations, 'vacuum_cleaner/normalizations'
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
module VacuumCleaner
|
|
2
|
+
|
|
3
|
+
# @private
|
|
2
4
|
# Suffix added to existing setter methods
|
|
3
5
|
WITHOUT_NORMALIZATION_SUFFIX = "_without_normalization"
|
|
4
6
|
|
|
7
|
+
# Base module required to be included in
|
|
8
|
+
#
|
|
5
9
|
module Normalizations
|
|
6
10
|
|
|
7
11
|
def self.included(base)
|
|
@@ -9,6 +13,27 @@ module VacuumCleaner
|
|
|
9
13
|
end
|
|
10
14
|
|
|
11
15
|
module ClassMethods
|
|
16
|
+
|
|
17
|
+
# Enables normalization chain for supplied attributes.
|
|
18
|
+
#
|
|
19
|
+
# @example Basic usage for plain old ruby objects.
|
|
20
|
+
# class Doctor
|
|
21
|
+
# include VacuumCleaner::Normalizations
|
|
22
|
+
# attr_accessor :name
|
|
23
|
+
# normalizes :name
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
#
|
|
27
|
+
# @param [Strings, Symbols] attributes list of attribute names to normalize, at least one attribute is required
|
|
28
|
+
# @param [Hash] options optional list of normalizers to use, like +:downcase => true+. To not run the default
|
|
29
|
+
# normalizer ({VacuumCleaner::Normalizer#normalize_value}) set +:default => false+
|
|
30
|
+
#
|
|
31
|
+
# @yield [value] optional block to define some one-time custom normalization logic
|
|
32
|
+
# @yieldparam value can be +nil+, otherwise value as passed through the default normalizer
|
|
33
|
+
# @yieldreturn should return value as normalized by the block
|
|
34
|
+
#
|
|
35
|
+
# @yield [instance, attribute, value] optional (extended) block with all arguments, like the +object+ and
|
|
36
|
+
# current +attribute+ name. Everything else behaves the same es the single-value +yield+
|
|
12
37
|
def normalizes(*attributes, &block)
|
|
13
38
|
metaklass = class << self; self; end
|
|
14
39
|
|
|
@@ -38,8 +63,8 @@ module VacuumCleaner
|
|
|
38
63
|
rb_src = <<-RUBY
|
|
39
64
|
def #{attribute}=(value) # 1. def name=(value)
|
|
40
65
|
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(:'
|
|
42
|
-
return
|
|
66
|
+
return send(#{original_setter.inspect}, value) if respond_to?(#{original_setter.inspect}) # 3. return send(:'name_wi...=', value) if respond_to?(:'name_wi...=')
|
|
67
|
+
return self[#{attribute.inspect}] = value if respond_to?(:[]=) # 4. return self[:name] = value if respond_to?(:write_attribute)
|
|
43
68
|
@#{attribute} = value # 5. @name = value
|
|
44
69
|
end # 6. end
|
|
45
70
|
RUBY
|
|
@@ -50,6 +75,7 @@ module VacuumCleaner
|
|
|
50
75
|
end
|
|
51
76
|
end
|
|
52
77
|
|
|
78
|
+
# @private
|
|
53
79
|
# Okay, because this library currently does not depend on
|
|
54
80
|
# <tt>ActiveSupport</tt> or anything similar an "independent" camelizing process is
|
|
55
81
|
# required.
|
|
@@ -13,10 +13,7 @@ module VacuumCleaner
|
|
|
13
13
|
# Subclasses of the +MethodNormalizer+ can take advantage of it's
|
|
14
14
|
# +normalize_if_respond_to+ method, to easily create custom
|
|
15
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
|
-
|
|
16
|
+
class MethodNormalizer < Normalizer
|
|
20
17
|
# Helper method to "bake" a method normalizer from a method, enabling us to do stuff like.
|
|
21
18
|
#
|
|
22
19
|
# TitelizeNormalizer = MethodNormalizer.build(:titleize)
|
|
@@ -31,11 +28,11 @@ module VacuumCleaner
|
|
|
31
28
|
super(args)
|
|
32
29
|
end
|
|
33
30
|
|
|
34
|
-
# Normalize value by
|
|
35
|
-
#
|
|
31
|
+
# Normalize value by trying to call the method at hand, if
|
|
32
|
+
# +value+ does not respond to the defined method, returns +nil+.
|
|
36
33
|
def normalize_value(value)
|
|
37
34
|
sym = options[:method]
|
|
38
|
-
value.respond_to?(sym) ? value.send(sym) :
|
|
35
|
+
value.respond_to?(sym) ? value.send(sym) : nil
|
|
39
36
|
end
|
|
40
37
|
end
|
|
41
38
|
|
|
@@ -1,17 +1,38 @@
|
|
|
1
1
|
module VacuumCleaner
|
|
2
2
|
module Normalizations
|
|
3
3
|
|
|
4
|
-
#
|
|
4
|
+
# Normalizer which is used to prefix strings with a scheme, if missing.
|
|
5
|
+
# This is useful to ensure, that an input field always has e.g. the
|
|
6
|
+
# "http://" scheme added. Please note, that this normalizer does not
|
|
7
|
+
# validate a URL in any way.
|
|
5
8
|
#
|
|
9
|
+
# normalizes :homepage, :url => true
|
|
6
10
|
#
|
|
11
|
+
# Accepts a string as input, so to normalize for instance FTP URLs.
|
|
12
|
+
#
|
|
13
|
+
# normalizes :download_url, :url => "ftp://"
|
|
14
|
+
#
|
|
15
|
+
# To make further customizations, the constructor accepts a hash.
|
|
16
|
+
#
|
|
17
|
+
# normalizes, :contact_url, :url => { :scheme => "http://",
|
|
18
|
+
# :unless => %r{\A(https?://|xmpp:|gtalk:|mailto:)} }
|
|
19
|
+
#
|
|
20
|
+
# The key <tt>:scheme</tt> is always used as the prefix, when the input
|
|
21
|
+
# does not a match the regex in <tt>:unless</tt>.
|
|
7
22
|
class UrlNormalizer < Normalizer
|
|
23
|
+
|
|
24
|
+
# Accepts either a hash or a string.
|
|
8
25
|
def initialize(options = {})
|
|
9
26
|
options = { :scheme => "http://", :unless => %r{\Ahttps?://}i } if options.nil? || options.empty?
|
|
10
27
|
options = { :scheme => options, :unless => %r{\A#{options}}i } unless options.is_a?(Hash)
|
|
11
28
|
super(options)
|
|
12
29
|
end
|
|
13
30
|
|
|
31
|
+
# Prefixes input with <tt>options[:scheme]</tt> if it doesn't matches
|
|
32
|
+
# <tt>options[:unless]</tt>.
|
|
14
33
|
def normalize_value(value)
|
|
34
|
+
value = super # just ensure that default stripping/cleaning is done already
|
|
35
|
+
return nil if value == options[:scheme]
|
|
15
36
|
value =~ options[:unless] ? value : "#{options[:scheme]}#{value}" unless value.nil?
|
|
16
37
|
end
|
|
17
38
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module VacuumCleaner
|
|
1
|
+
module VacuumCleaner
|
|
2
2
|
|
|
3
3
|
# A small base class for implementing custom value normalizers.
|
|
4
4
|
# Might seem like a slight overkill, yet makes the library pretty
|
|
@@ -46,7 +46,7 @@ module VacuumCleaner #:nodoc:
|
|
|
46
46
|
# +normalize_value+.
|
|
47
47
|
#
|
|
48
48
|
# This can be used together with the +normalizes+ method (see
|
|
49
|
-
#
|
|
49
|
+
# VacuumCleaner::Normalizers#normalizes for more on this).
|
|
50
50
|
class Normalizer
|
|
51
51
|
# Options as supplied to the normalizer.
|
|
52
52
|
attr_reader :options
|
|
@@ -59,7 +59,7 @@ module VacuumCleaner #:nodoc:
|
|
|
59
59
|
# Only override this method if access to the <tt>object</tt> or <tt>attribute</tt> name
|
|
60
60
|
# is required, else override +normalize_value+, makes life much simpler :)
|
|
61
61
|
#
|
|
62
|
-
# Default behaviour just calls
|
|
62
|
+
# Default behaviour just calls #normalize_value.
|
|
63
63
|
def normalize(object, attribute, value); normalize_value(value) end
|
|
64
64
|
|
|
65
65
|
# Override this method in subclasses to specifiy custom normalization steps and magic.
|
data/rails/init.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
require 'vacuum_cleaner'
|
|
2
2
|
|
|
3
|
-
ActiveRecord::Base.class_eval { include VacuumCleaner::Normalizations } # all versions of rails
|
|
4
|
-
# ActiveModel::Base.class_eval { include VacuumCleaner::Normalizations } if defined?(ActiveModel::Base) # Rails 3+
|
|
3
|
+
ActiveRecord::Base.class_eval { include VacuumCleaner::Normalizations } if defined?(ActiveRecord::Base) # all versions of rails
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
# load ActiveRecord
|
|
4
|
+
require 'active_record'
|
|
5
|
+
|
|
6
|
+
# open connection to in-memory db
|
|
7
|
+
ActiveRecord::Base.establish_connection({
|
|
8
|
+
:adapter => RUBY_PLATFORM =~ /java/ ? 'jdbcsqlite3' : 'sqlite3',
|
|
9
|
+
:database => ':memory:'})
|
|
10
|
+
|
|
11
|
+
# run init.rb
|
|
12
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'init')
|
|
13
|
+
|
|
14
|
+
puts "Running integration tests against: active_record-#{ActiveRecord::VERSION::STRING}"
|
|
15
|
+
|
|
16
|
+
class ActiveRecordIntegrationTest < ::Test::Unit::TestCase
|
|
17
|
+
context "ActiveRecord::Base" do
|
|
18
|
+
should "include VacuumCleaner::Normalizations" do
|
|
19
|
+
assert ActiveRecord::Base.included_modules.include?(VacuumCleaner::Normalizations)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context "with a sqlite connection" do
|
|
23
|
+
setup do
|
|
24
|
+
# build db
|
|
25
|
+
ActiveRecord::Base.connection.create_table :dummies, :force => true do |t|
|
|
26
|
+
t.column :name, :string
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
should "respond to normalize and normalize :name on set" do
|
|
31
|
+
klass = Class.new(ActiveRecord::Base) do; set_table_name 'dummies'; normalizes :name end
|
|
32
|
+
|
|
33
|
+
object = klass.new({ :name => "Elliot Reid\n" })
|
|
34
|
+
assert_equal "Elliot Reid", object.name
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
should "normalize on +object.name+ accessors as well" do
|
|
38
|
+
klass = Class.new(ActiveRecord::Base) do; set_table_name 'dummies'; normalizes :name end
|
|
39
|
+
|
|
40
|
+
object = klass.new
|
|
41
|
+
object.name = " Dorian\t\n"
|
|
42
|
+
assert_equal "Dorian", object.name
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
should "not normalize when accessing directly using []/write_attribute" do
|
|
46
|
+
klass = Class.new(ActiveRecord::Base) do; set_table_name 'dummies'; normalizes :name end
|
|
47
|
+
object = klass.new
|
|
48
|
+
object[:name] = "Elliot Reid\n\t"
|
|
49
|
+
assert_equal "Elliot Reid\n\t", object.name
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
should "not normalize when reading from database" do
|
|
53
|
+
ActiveRecord::Base.connection.execute "INSERT INTO dummies VALUES(NULL,'Elliot Reid\n\t');"
|
|
54
|
+
klass = Class.new(ActiveRecord::Base) do; set_table_name 'dummies'; normalizes :name end
|
|
55
|
+
assert_equal "Elliot Reid\n\t", klass.last.name
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
should "work with customized setter methods, masking AR-attributes" do
|
|
59
|
+
klass = Class.new(ActiveRecord::Base) do; set_table_name 'dummies'; def name=(n); self[:name] = n; end; normalizes :name end
|
|
60
|
+
object = klass.new :name => " J.D.\n"
|
|
61
|
+
assert_equal "J.D.", object.name
|
|
62
|
+
object.name = "Dorian\n\r"
|
|
63
|
+
assert_equal "Dorian", object.name
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/test/test_helper.rb
CHANGED
|
@@ -17,6 +17,11 @@ class VacuumCleaner::Normalizations::MethodTest < Test::Unit::TestCase
|
|
|
17
17
|
assert_equal "ELLIOT\n", upcaser.normalize_value("Elliot\n")
|
|
18
18
|
assert_equal " \t", upcaser.normalize_value(" \t")
|
|
19
19
|
end
|
|
20
|
+
|
|
21
|
+
should "convert value to <nil> if object does not respond to supplied method" do
|
|
22
|
+
normalizer = MethodNormalizer.new(:this_method_does_certainly_not_exist)
|
|
23
|
+
assert_nil normalizer.normalize_value("Elliot")
|
|
24
|
+
end
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
context "DowncaseNormalizer#normalize_value" do
|
|
@@ -35,5 +35,14 @@ class VacuumCleaner::Normalizations::UrlTest < Test::Unit::TestCase
|
|
|
35
35
|
assert_equal "jabber:jd@sh.com", n.normalize_value("jabber:jd@sh.com")
|
|
36
36
|
assert_equal "https://docs.google.com", n.normalize_value("https://docs.google.com")
|
|
37
37
|
end
|
|
38
|
+
|
|
39
|
+
should "normalize to <nil> if only scheme is given" do
|
|
40
|
+
assert_nil UrlNormalizer.new.normalize_value("http://")
|
|
41
|
+
assert_nil UrlNormalizer.new.normalize_value(" http://\n")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
should "be stupid, so if some other scheme is used, just override it, haha" do
|
|
45
|
+
assert_equal "xmpp:mailto:jd@sacred-heart.com", UrlNormalizer.new("xmpp:").normalize_value("mailto:jd@sacred-heart.com")
|
|
46
|
+
end
|
|
38
47
|
end
|
|
39
48
|
end
|
metadata
CHANGED
|
@@ -3,10 +3,10 @@ name: vacuum_cleaner
|
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
|
5
5
|
segments:
|
|
6
|
+
- 1
|
|
6
7
|
- 0
|
|
7
|
-
- 5
|
|
8
8
|
- 0
|
|
9
|
-
version: 0.
|
|
9
|
+
version: 1.0.0
|
|
10
10
|
platform: ruby
|
|
11
11
|
authors:
|
|
12
12
|
- Lukas Westermann
|
|
@@ -14,7 +14,7 @@ autorequire:
|
|
|
14
14
|
bindir: bin
|
|
15
15
|
cert_chain: []
|
|
16
16
|
|
|
17
|
-
date: 2010-
|
|
17
|
+
date: 2010-04-21 00:00:00 +02:00
|
|
18
18
|
default_executable:
|
|
19
19
|
dependencies:
|
|
20
20
|
- !ruby/object:Gem::Dependency
|
|
@@ -31,24 +31,10 @@ dependencies:
|
|
|
31
31
|
version: 2.10.2
|
|
32
32
|
type: :development
|
|
33
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
34
|
- !ruby/object:Gem::Dependency
|
|
49
35
|
name: activesupport
|
|
50
36
|
prerelease: false
|
|
51
|
-
requirement: &
|
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
52
38
|
requirements:
|
|
53
39
|
- - ">="
|
|
54
40
|
- !ruby/object:Gem::Version
|
|
@@ -58,7 +44,7 @@ dependencies:
|
|
|
58
44
|
- 5
|
|
59
45
|
version: 2.3.5
|
|
60
46
|
type: :development
|
|
61
|
-
version_requirements: *
|
|
47
|
+
version_requirements: *id002
|
|
62
48
|
description: Ruby (and Rails) attribute cleaning support, provides some nice and easy to enhance default normalization strategies.
|
|
63
49
|
email: lukas.westermann@gmail.com
|
|
64
50
|
executables: []
|
|
@@ -79,6 +65,7 @@ files:
|
|
|
79
65
|
- lib/vacuum_cleaner/normalizations/url.rb
|
|
80
66
|
- lib/vacuum_cleaner/normalizer.rb
|
|
81
67
|
- rails/init.rb
|
|
68
|
+
- test/integration/active_record_integration_test.rb
|
|
82
69
|
- test/test_helper.rb
|
|
83
70
|
- test/unit/vacuum_cleaner/normalizations/method_test.rb
|
|
84
71
|
- test/unit/vacuum_cleaner/normalizations/url_test.rb
|
|
@@ -115,6 +102,7 @@ signing_key:
|
|
|
115
102
|
specification_version: 3
|
|
116
103
|
summary: Ruby (and Rails) attribute cleaning support, provides some nice default normalization strategies.
|
|
117
104
|
test_files:
|
|
105
|
+
- test/integration/active_record_integration_test.rb
|
|
118
106
|
- test/test_helper.rb
|
|
119
107
|
- test/unit/vacuum_cleaner/normalizations/method_test.rb
|
|
120
108
|
- test/unit/vacuum_cleaner/normalizations/url_test.rb
|