Skip to content
This repository has been archived by the owner on Dec 24, 2020. It is now read-only.

Commit

Permalink
Add initial extensions for Hash/Array/String and m method on Object
Browse files Browse the repository at this point in the history
  • Loading branch information
onsitedev committed Oct 27, 2010
1 parent 7193fe8 commit a03ab4a
Show file tree
Hide file tree
Showing 17 changed files with 485 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
pkg/*
*.gem
.bundle
5 changes: 4 additions & 1 deletion Gemfile
@@ -1,4 +1,7 @@
source "http://rubygems.org" source "http://rubygems.org"


# Specify your gem's dependencies in libraries.gemspec
gemspec gemspec

group :test do
gem "rspec"
end
26 changes: 26 additions & 0 deletions Gemfile.lock
@@ -0,0 +1,26 @@
PATH
remote: .
specs:
libraries (0.0.1)

GEM
remote: http://rubygems.org/
specs:
diff-lcs (1.1.2)
rspec (2.0.1)
rspec-core (~> 2.0.1)
rspec-expectations (~> 2.0.1)
rspec-mocks (~> 2.0.1)
rspec-core (2.0.1)
rspec-expectations (2.0.1)
diff-lcs (>= 1.1.2)
rspec-mocks (2.0.1)
rspec-core (~> 2.0.1)
rspec-expectations (~> 2.0.1)

PLATFORMS
ruby

DEPENDENCIES
libraries!
rspec
10 changes: 10 additions & 0 deletions Rakefile
@@ -1,2 +1,12 @@
require 'bundler' require 'bundler'
Bundler::GemHelper.install_tasks Bundler::GemHelper.install_tasks

require 'spec/rake/spectask'

task :default => :spec

desc "Run specs"
Spec::Rake::SpecTask.new do |t|
t.spec_files = FileList['spec/**/*_spec.rb']
t.spec_opts = %w(-fs --color)
end
8 changes: 6 additions & 2 deletions lib/libraries.rb
@@ -1,3 +1,7 @@
module Libraries require "active_support"


end require "libraries/enumerable"
require "libraries/array"
require "libraries/hash"
require "libraries/string"
require "libraries/object"
42 changes: 42 additions & 0 deletions lib/libraries/active_record.rb
@@ -0,0 +1,42 @@
module ActiveRecord

class Base
before_save(:_clean_whitespace)

def _clean_whitespace
self.attributes.each_pair do |key, value|
if value && value.respond_to?('strip')
self[key] = value.strip
end
end
end

def to_hash(*fields)
h = attributes.symbolize_keys
fields.present? ? h.slice(*fields.flatten) : h
end

class << self
def conditions(*args)
scoped :conditions => args
end

def by_date_range(options)
scoped :conditions => ["#{options[:date_field]} BETWEEN ? AND ?", options[:start_date].to_s(:db), (options[:end_date] || Date.today).to_s(:db)]
end

def sort_scope(options)
scoped :order => "#{options[:attribute]} #{options[:direction]}"
end

def random(_limit=1)
scoped :order => "RAND()", :limit => _limit
end

def limit(_limit)
scoped :limit => _limit
end
end
end

end
17 changes: 17 additions & 0 deletions lib/libraries/array.rb
@@ -0,0 +1,17 @@
class Array

def each_pair
self.in_groups_of(2).each { |g| yield g.first, g.last }
end

# delete all passed element and return the array after delete
def delete!(*args)
self.tap { |a| a.delete_if { |e| args.include? e } }
end

# same as delete! but does not alter self
def without(*args)
self.dup.tap { |dup| dup.delete!(*args) }
end

end
15 changes: 15 additions & 0 deletions lib/libraries/enumerable.rb
@@ -0,0 +1,15 @@
module Enumerable

# Call the given block for each element, creating a new hash
# that uses the element as the key and the block's result as the value.
def map_into_hash &block
# The "reduce(:concat)" does a shallow flatten, so that blocks that
# return arrays will do the Right Thing.
Hash[*map {|x| [x, block.call(x)]}.inject([], &:concat)]
end

def map_keyvals_into_hash &block
Hash[*map(&block).inject([], &:concat)]
end

end
73 changes: 73 additions & 0 deletions lib/libraries/hash.rb
@@ -0,0 +1,73 @@
class Hash

def recursive_symbolize_keys!
symbolize_keys!
# symbolize each hash in .values
values.each{|h| h.recursive_symbolize_keys! if h.is_a?(Hash) }
# symbolize each hash inside an array in .values
values.select{|v| v.is_a?(Array) }.flatten.each{|h| h.recursive_symbolize_keys! if h.is_a?(Hash) }
self
end

# deep lookup a nested hash without failing on non-existing keys
# in which case returns and empty hash
# This will only work on NESTED hashes, something like:
# h = {:a => {:b => {:c => 3}}}
# h.lookup(:a,:b,:c) => 3
# h.lookup(:a,:b) => {:c => 3}
# h.lookup(:a,:b,:X) => nil
# h.lookup(:a,:X,:Y) => nil
# h.lookup(:W,:T,:F) => nil
def nested_lookup(*keys)
keys.inject(self){ |h,k| (h || {}).fetch(k,nil) } rescue nil
end

# Takes a hash argument of old, new pairs
# Returns hash with keys renamed
def rename_keys!(keys_hash)
keys_hash.each do |old, new|
self[new] = self.delete(old)
end
self
end

def rename_keys(keys_hash)
self.dup.rename_keys!(keys_hash)
end

# map from a block
def map_into_hash(&block)
Hash[*map {|x| [x[0], block.call(x)]}.inject([], &:concat)]
end

def parent_to?(*args)
return self.slice(*args.first.keys) == args.first if args.size == 1 && args.first.is_a?(Hash)
args.each_pair do |key, value|
return false unless self[key] == value
end
true
end

############################################################
# The following methods take as an argument, a list of keys
# See the specs for examples

def all_keys?(*keys)
keys.all? {|k| has_key? k}
end

def any_key?(*keys)
keys.any? {|k| has_key? k}
end

def all_values?(*keys)
keys.all?{|k| self[k].present?}
end

def any_value?(*keys)
keys.any?{|k| self[k].present?}
end

############################################################

end
9 changes: 9 additions & 0 deletions lib/libraries/object.rb
@@ -0,0 +1,9 @@
class Object

def m regexp=nil
m = (self.methods - Object.methods).sort
return m.grep(/#{regexp}/) if regexp
m
end

end
32 changes: 32 additions & 0 deletions lib/libraries/string.rb
@@ -0,0 +1,32 @@
class String

def strip_with_arg_support!(char=nil)
if char.present?
m = char.each_char.inject('') {|r,c| r+=(c =~ /[\*\.\[\]\^\$\?\\\|\=\+\:\/\(\)]/ ? "\\" : "") + c}
self.gsub!(/^[#{m}]*(.*?)[#{m}]*$/,'\1')
else
strip_without_arg_support!
end
end
alias_method_chain :strip!, :arg_support

def strip_with_arg_support(char=nil)
char.present? ? self.dup.strip!(char) : strip_without_arg_support
end
alias_method_chain :strip, :arg_support

# In the sense of normal characters only, it also downcases the string
# Can be used, for example, in file names and css classes
def normalize!
return if normalize.blank?
self.gsub!(/[^A-Z0-9]/i, '_')
self.squeeze!("_")
self.strip!("_")
self.downcase!
end

def normalize
self.gsub(/[^A-Z0-9]/i, '_').squeeze("_").strip("_").downcase
end

end
2 changes: 2 additions & 0 deletions lib/rails.rb
@@ -0,0 +1,2 @@
require "libraries"
require "libraries/active_record" if defined?(ActiveRecord)
35 changes: 35 additions & 0 deletions spec/libraries/array_spec.rb
@@ -0,0 +1,35 @@
require 'spec_helper'

describe Array do

describe "#each_pair" do
it "yeilds pairs" do
out = ''
[1,2,3,4].each_pair { |a1,a2| out << "*#{a1}#{a2}*" }
out.should == "*12**34*"
end
end

describe "#delete!" do
it "accepts one argument and returns the array after delete" do
[1,:a,3.14,"x"].delete!(1).should == [:a,3.14,"x"]
end
it "accepts a list of arguments and returns the array after delete" do
[1,:a,3.14,"x"].delete!(1, "x").should == [:a,3.14]
end
it "modifies receiver" do
a = [1,2,3]
a.delete!(2,3)
a.should == [1]
end
end

describe "#without" do
it "does not modify receiver" do
a = [1,2,3]
a.without(2,3).should == [1]
a.should == [1,2,3]
end
end

end

0 comments on commit a03ab4a

Please sign in to comment.