Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial import of vacuum cleaner repository
- Loading branch information
0 parents
commit 533abf9
Showing
11 changed files
with
649 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
Copyright (c) 2009 Lukas Westermann | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining | ||
a copy of this software and associated documentation files (the | ||
"Software"), to deal in the Software without restriction, including | ||
without limitation the rights to use, copy, modify, merge, publish, | ||
distribute, sublicense, and/or sell copies of the Software, and to | ||
permit persons to whom the Software is furnished to do so, subject to | ||
the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
require 'rake' | ||
require 'rake/testtask' | ||
require 'yard' | ||
|
||
#def gravatarify_version | ||
# @gravatarify_version ||= (tmp = YAML.load(File.read('VERSION.yml'))) && [tmp[:major], tmp[:minor], tmp[:patch]] * '.' | ||
#end | ||
|
||
desc 'Default: run unit tests.' | ||
task :default => :test | ||
|
||
desc 'Test the vacuum_cleaner plugin.' | ||
Rake::TestTask.new(:test) do |t| | ||
t.libs << 'lib' | ||
t.libs << 'test' | ||
t.pattern = 'test/**/*_test.rb' | ||
t.verbose = true | ||
end | ||
|
||
desc 'Generate documentation for vacuum_cleaner. (requires yard)' | ||
YARD::Rake::YardocTask.new(:doc) do |t| | ||
t.files = ['lib/**/*.rb'] | ||
t.options = [ | ||
"--readme", "README.md", | ||
"--title", "vacuum_cleaner (vBETA) API Documentation" | ||
] | ||
end | ||
|
||
begin | ||
require 'jeweler' | ||
Jeweler::Tasks.new do |gemspec| | ||
gemspec.name = "vacuum_cleaner" | ||
gemspec.summary = "TODO" | ||
description = <<-DESC | ||
TODO | ||
DESC | ||
gemspec.description = description.strip | ||
gemspec.email = "lukas.westermann@gmail.com" | ||
gemspec.homepage = "http://github.com/lwe/vacuum_cleaner" | ||
gemspec.authors = ["Lukas Westermann"] | ||
gemspec.licenses = %w{LICENSE} | ||
gemspec.extra_rdoc_files = %w{README.md} | ||
|
||
gemspec.add_development_dependency('shoulda', '>= 2.10.2') | ||
gemspec.add_development_dependency('rr', '>= 0.10.5') | ||
gemspec.add_development_dependency('activesupport', '>= 2.3.5') | ||
end | ||
Jeweler::GemcutterTasks.new | ||
rescue LoadError | ||
puts "Jeweler not available. Install it with: sudo gem install jeweler" | ||
end | ||
|
||
desc 'Clean all generated files (.yardoc and doc/*)' | ||
task :clean do |t| | ||
FileUtils.rm_rf "doc" | ||
FileUtils.rm_rf "pkg" | ||
FileUtils.rm_rf "*.gemspec" | ||
FileUtils.rm_rf ".yardoc" | ||
end | ||
|
||
namespace :metrics do | ||
desc 'Report all metrics, i.e. stats and code coverage.' | ||
task :all => [:stats, :coverage] | ||
|
||
desc 'Report code statistics for library and tests to shell.' | ||
task :stats do |t| | ||
require 'code_statistics' | ||
dirs = { | ||
'Libraries' => 'lib', | ||
'Unit tests' => 'test/unit' | ||
}.map { |name,dir| [name, File.join(File.dirname(__FILE__), dir)] } | ||
CodeStatistics.new(*dirs).to_s | ||
end | ||
|
||
desc 'Report code coverage to HTML (doc/coverage) and shell (requires rcov).' | ||
task :coverage do |t| | ||
rm_f "doc/coverage" | ||
mkdir_p "doc/coverage" | ||
rcov = %(rcov -Ilib:test --exclude '\/gems\/' -o doc/coverage -T test/unit/*_test.rb ) | ||
system rcov | ||
end | ||
|
||
desc 'Report the fishy smell of bad code (requires reek)' | ||
task :smelly do |t| | ||
puts | ||
puts "* * * NOTE: reek currently reports several false positives," | ||
puts " eventhough it's probably good to check once in a while!" | ||
puts | ||
reek = %(reek -s lib) | ||
system reek | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
module VacuumCleaner | ||
module Normalizations | ||
WITHOUT_NORMALIZATION_SUFFIX = "_without_normalization" | ||
|
||
def self.included(base) | ||
base.extend(ClassMethods) | ||
end | ||
|
||
module ClassMethods | ||
def normalizes(*attributes, &block) | ||
metaklass = class << self; self; end | ||
|
||
normalizations = attributes.last.is_a?(Hash) ? attributes.pop : {} | ||
raise ArgumentError, "You need to supply at least one attribute" if attributes.empty? | ||
|
||
normalizers = [] | ||
normalizers << Normalizer.new unless normalizations.delete(:default) === false | ||
|
||
normalizations.each do |key, options| | ||
begin | ||
#klass = "#{Inflector.camelize(key)}Normalizer" | ||
#klass = const_defined?(klass) ? const_get(klass) : (Object.const_defined?(klass) ? Object.const_get(klass) : eval("VacuumCleaner::Normalizations::#{klass}")) | ||
normalizers << const_get("#{Inflector.camelize(key)}Normalizer").new(options === true ? {} : options) | ||
rescue NameError | ||
raise ArgumentError, "Unknown normalizer: '#{key}'" | ||
end | ||
end | ||
|
||
attributes.each do |attribute| | ||
rb_src = unless instance_methods.include?("#{attribute}=") | ||
"@#{attribute} = value" | ||
else | ||
send(:alias_method, "#{attribute}#{VacuumCleaner::Normalizations::WITHOUT_NORMALIZATION_SUFFIX}=", "#{attribute}=") | ||
"send('#{attribute}#{VacuumCleaner::Normalizations::WITHOUT_NORMALIZATION_SUFFIX}=', value)" | ||
end | ||
|
||
metaklass.send(:define_method, :"normalize_#{attribute}") do |value| | ||
value = normalizers.inject(value) { |v,n| n.normalize(self, attribute.to_sym, v) } | ||
block_given? ? (block.arity == 1 ? yield(value) : yield(self, attribute.to_sym, value)) : value | ||
end | ||
|
||
module_eval "def #{attribute}=(value); value = self.class.send(:'normalize_#{attribute}', value); #{rb_src} end", __FILE__, __LINE__ | ||
end | ||
end | ||
end | ||
|
||
module Inflector | ||
# Call either <tt>value.to_s.camelize</tt> if it responds to <tt>:camelize</tt>, else | ||
# simple implementation taken directly from http://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L25 | ||
# of a default camelize behaviour. | ||
def self.camelize(value) | ||
value = value.to_s | ||
value.respond_to?(:camelize) ? value.camelize : value.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } | ||
end | ||
end | ||
end | ||
end | ||
|
||
# load standard normalizations | ||
Dir[File.dirname(__FILE__) + "/normalizations/*.rb"].sort.each do |path| | ||
require "vacuum_cleaner/normalizations/#{File.basename(path)}" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
module VacuumCleaner | ||
module Normalizations | ||
|
||
# Generic method based normalizer which just calls supplied method | ||
# on value (unless nil). | ||
# | ||
# normalizes :name, :method => :titelize | ||
# | ||
# Custom instances accept a <tt>:method</tt> option. | ||
# | ||
# MethodNormalizer.new(:method => :titelize) | ||
# | ||
# Subclasses of the +MethodNormalizer+ can take advantage of it's | ||
# +normalize_if_respond_to+ method, to easily create custom | ||
# normalizers based on methods availble on the result value. | ||
class MethodNormalizer < Normalizer | ||
# Ensure access to default normalization method | ||
alias_method :default_normalize_value, :normalize_value | ||
|
||
# Helper method to "bake" a method normalizer from a method, enabling us to do stuff like. | ||
# | ||
# TitelizeNormalizer = MethodNormalizer.build(:titleize) | ||
# | ||
def self.build(sym) | ||
module_eval "Class.new(MethodNormalizer) do; def initialize(*args); super({ :method => #{sym.inspect}}) end; end", __FILE__, __LINE__ | ||
end | ||
|
||
# Accept either a hash or symbol name. | ||
def initialize(args = {}) | ||
args = { :method => args } unless args.is_a?(Hash) | ||
super(args) | ||
end | ||
|
||
# Normalize value by calling the default normalizer (strip + nil if empty) | ||
# and then if not <tt>nil</tt> call the method defined. | ||
def normalize_value(value) | ||
sym = options[:method] | ||
value.respond_to?(sym) ? value.send(sym) : value | ||
end | ||
end | ||
|
||
# Downcase value unless nil or empty. | ||
DowncaseNormalizer = MethodNormalizer.build(:downcase) | ||
|
||
# Upcases value unless nil or empty. | ||
UpcaseNormalizer = MethodNormalizer.build(:upcase) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
module VacuumCleaner #:nodoc: | ||
|
||
# A small base class for implementing custom value normalizers. | ||
# Might seem like a slight overkill, yet makes the library pretty | ||
# reusable and all. Based on Rails 3 validator stuff. | ||
# | ||
# | ||
# class Person | ||
# include VacuumCleaner::Normalizations | ||
# normalizes :name, :titleize => true | ||
# end | ||
# | ||
# class TitleizeNormalizer < VacuumCleaner::Normalizer | ||
# def normalize_value(value) | ||
# value.titelize unless value.blank? | ||
# end | ||
# end | ||
# | ||
# Any class that inherits from +VacuumCleaner::Normalizer+ must implement | ||
# a method called <tt>normalize_value</tt> which accepts the <tt>value</tt> to normalize. Furthermore | ||
# the value returned by <tt>normalize</tt> is used as the new value for | ||
# the attribute. | ||
# | ||
# To reuse the behaviour as defined by the default normalizer (strip & empty), | ||
# just use <tt>super</tt>. | ||
# | ||
# class TitleizeNormalizer < VacuumCleaner::Normalizer | ||
# def normalize_value(value) | ||
# super(value).try(:titelize) | ||
# end | ||
# end | ||
# | ||
# If access to the record or attribute being normalized is required the method | ||
# +normalize+ can be overriden instead. | ||
# | ||
# class FancyNormalizer < VacuumCleaner::Normalizer | ||
# def normalize(object, attribute, value) | ||
# ... | ||
# end | ||
# end | ||
# | ||
# This can be used together with the +normalizes+ method (see | ||
# VacuumCleaner::Normalizers.normalizes for more on this). | ||
class Normalizer | ||
attr_reader :options | ||
|
||
# Accepts an array of options, which will be made available through the +options+ reader. | ||
def initialize(options = {}) | ||
@options = options | ||
end | ||
|
||
# Only override this method if access to the <tt>object</tt> or <tt>attribute</tt> name | ||
# is required, else override +normalize_value+, makes life much simpler :) | ||
# | ||
# Default behaviour just calls <tt>normalize_value(value)</tt>. | ||
def normalize(object, attribute, value); normalize_value(value) end | ||
|
||
# Override this method in subclasses to specifiy custom normalization steps and magic. | ||
# | ||
# The standard implementation strips the value of trailing/leading whitespace and then | ||
# either returns that value or +nil+ if it's <tt>empty?</tt>. | ||
def normalize_value(value) | ||
value = value.strip if value.respond_to?(:strip) | ||
value.nil? || (value.respond_to?(:empty?) && value.empty?) ? nil : value | ||
end | ||
end | ||
end |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
require 'rubygems' | ||
require 'test/unit' | ||
require 'shoulda' | ||
require 'rr' | ||
|
||
# require 'normalo' | ||
|
||
Test::Unit::TestCase.send(:include, RR::Adapters::TestUnit) | ||
|
||
# Dir[File.dirname(__FILE__) + "/fixtures/*.rb"].each { |fixture| require fixture } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
require 'test_helper' | ||
|
||
class NormaloTest < Test::Unit::TestCase | ||
context "`extend Normalo`" do | ||
should "provide #normalize to anonymous class" do | ||
assert_respond_to Class.new { extend Normalo::Normalizer }, :normalize | ||
end | ||
end | ||
|
||
context "#normalize" do | ||
should "take a symbol as argument" do | ||
assert_respond_to Class.new { extend Normalo::Normalizer; normalize(:name) }, :normalize | ||
end | ||
|
||
should "take multiple symbols as argument" do | ||
klass = Class.new { extend Normalo::Normalizer; normalize(:name, :first_name) } | ||
assert_respond_to klass, :normalize | ||
assert_respond_to klass, :normalize_name | ||
assert_respond_to klass, :normalize_first_name | ||
end | ||
|
||
should "create a setter for supplied attribute" do | ||
obj = Class.new { extend Normalo::Normalizer; normalize(:name) }.new | ||
assert_respond_to obj, :name= | ||
end | ||
|
||
should "set the instance variable using the setter" do | ||
obj = Class.new { extend Normalo::Normalizer; normalize(:name) }.new | ||
obj.name = "J.D." | ||
assert_equal "J.D.", obj.instance_variable_get(:@name) | ||
end | ||
|
||
should "alias method to <attr>_without_normalization= if <attr>= already defined" do | ||
klass = Class.new do | ||
extend Normalo::Normalizer | ||
def name=(name); @foo = name end | ||
normalize :name | ||
end | ||
obj = klass.new | ||
obj.name = "Elliot Reid" | ||
assert_respond_to obj, :name_without_normalization= | ||
assert_equal "Elliot Reid", obj.instance_variable_get(:@foo) | ||
assert_nil obj.instance_variable_get(:@name) | ||
end | ||
|
||
should "convert any blank input, like empty string, nil etc. to => <nil>" do | ||
obj = Person.new | ||
obj.first_name = " " | ||
obj.last_name = '' | ||
assert_nil obj.first_name | ||
assert_nil obj.last_name | ||
end | ||
|
||
should "strip leading and trailing white-space" do | ||
obj = Person.new | ||
obj.first_name = "\nElliot\t " | ||
obj.last_name = nil | ||
assert_nil obj.last_name | ||
assert_equal "Elliot", obj.first_name | ||
end | ||
|
||
should "accept a block which overrides the default to_nil_if_empty strategy" do | ||
klass = Class.new do | ||
extend Normalo::Normalizer | ||
attr_accessor :name | ||
normalize :name do |value| | ||
value = value.to_nil_if_empty | ||
value ? value.upcase : value | ||
end | ||
end | ||
obj = klass.new | ||
obj.name = "Turk" | ||
assert_equal "TURK", obj.name | ||
end | ||
end | ||
end |
Oops, something went wrong.