Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 211989b
Showing
21 changed files
with
424 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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,2 @@ | |||
source :rubygems | |||
gemspec |
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,65 @@ | |||
Sane tools for Ruby without monkey-patching. This is basically code usually | |||
copy from one project to another. | |||
|
|||
Goal of this library is to be lightweight and unobtrusive, so you don't have | |||
to feel guilty for using it. Mixins are lazy-loaded. | |||
|
|||
# Included Tools | |||
|
|||
## Tool::Autoloader | |||
|
|||
Sets up `autoload` directives for nested constants. Has the advantage of | |||
setting these up when included instead of hooking into `const_missing`, like | |||
ActiveSupport does. The means it is fast, transparent, and does not alter | |||
constant lookup in any way. | |||
|
|||
``` ruby | |||
module Foo | |||
include Tool::Autoloader | |||
end | |||
``` | |||
|
|||
If you don't want to include the module, use `setup`: | |||
|
|||
``` ruby | |||
Tool::Autoloader.setup Foo | |||
``` | |||
|
|||
## Tool::Lock | |||
|
|||
Adds a `synchronize` method that behaves like `Rubinius.synchronize(self)`, | |||
i.e. recursively going through the lock will not result in a deadlock: | |||
|
|||
``` ruby | |||
class Foo | |||
include Tool::Lock | |||
|
|||
def recursive_fun(i = 0) | |||
return i if i == 5 | |||
# THIS NEEDS TO BE THREAD-SAFE!!! | |||
synchronize { recursive_fun(i + 1) } | |||
end | |||
end | |||
``` | |||
|
|||
It will use `Rubinius.synchronize` when on Rubinius. | |||
|
|||
## Tool.set | |||
|
|||
Simplified version of Sinatra's set: | |||
|
|||
``` ruby | |||
class Foo | |||
Tool.set(self, :foo, :foo) | |||
end | |||
|
|||
class Bar < Foo | |||
end | |||
|
|||
Bar.foo # => :foo | |||
|
|||
Bar.foo = :bar | |||
Bar.foo # => :bar | |||
|
|||
Foo.foo # => :foo | |||
``` |
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,21 @@ | |||
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__) | |||
require 'tool/version' | |||
|
|||
def gem(*args) sh("gem", *args.map(&:to_s)) end | |||
def git(*args) sh("git", *args.map(&:to_s)) end | |||
|
|||
gem_file = "tool-#{Tool::VERSION}.gem" | |||
version = "v#{Tool::VERSION}" | |||
message = "Release #{version}" | |||
|
|||
task(:spec) { ruby "-S rspec spec" } | |||
task(:build) { gem :build, 'tool.gemspec' } | |||
task(:install => :build) { gem :install, gem_file } | |||
task(:publish => :install) { gem :push, gem_file } | |||
task(:commit) { git :commit, '--allow-empty', '-m', message } | |||
task(:tag) { git :tag, '-s', '-m', message, version } | |||
task(:push) { git :push } | |||
|
|||
task :release => [:spec, :commit, :publish, :tag, :push] | |||
task :default => :spec | |||
task :test => :spec |
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,17 @@ | |||
module Tool | |||
autoload :Autoloader, 'tool/autoloader' | |||
autoload :Lock, 'tool/lock' | |||
autoload :VERSION, 'tool/version' | |||
|
|||
def self.set(object, key, value = (no_value = true), &block) | |||
return key.each_pair { |k,v| set(object, k, v) } if no_value and not block | |||
|
|||
block = proc { value } unless no_value | |||
sclass = (class << object; self; end) | |||
setter = self | |||
|
|||
sclass.send(:define_method, key, &block) | |||
sclass.send(:define_method, "#{key}=") { |v| setter.set(self, key, v) } | |||
sclass.send(:define_method, "#{key}?") { !!__send__(key) } | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,60 @@ | |||
module Tool | |||
module Autoloader | |||
CAPITALIZE = %w[version cli] unless defined? CAPITALIZE | |||
|
|||
def self.setup(container, path = caller_dir) | |||
prefix = path_for(container) | |||
full_prefix = path_for(container, true) | |||
path = File.expand_path(prefix, path) | |||
directories = [] | |||
|
|||
Dir.glob("#{path}/*") do |file| | |||
base = File.basename(file, '.rb') | |||
const = constant_for(base) | |||
lib = "#{full_prefix}/#{base}" | |||
|
|||
if File.directory? file | |||
directories << const | |||
elsif file.end_with? '.rb' | |||
container.autoload const, lib | |||
end | |||
end | |||
|
|||
directories.each do |const| | |||
next if container.const_defined? const | |||
nested = container.const_set(const, Module.new) | |||
setup nested, path | |||
end | |||
end | |||
|
|||
def self.path_for(constant, full = false) | |||
name = constant.name.dup | |||
name = name[/[^:]+$/] unless full | |||
name.gsub! /([A-Z]+)([A-Z][a-z])/,'\1_\2' | |||
name.gsub! /([a-z\d])([A-Z])/,'\1_\2' | |||
name.gsub! '::', '/' | |||
name.tr("-", "_").downcase | |||
end | |||
|
|||
def self.constant_for(file) | |||
return file.upcase if CAPITALIZE.include? file | |||
file.split('.', 2).first.split(/[_-]/).map(&:capitalize).join | |||
end | |||
|
|||
def self.capitalize(*args) | |||
CAPITALIZE.concat(args) | |||
end | |||
|
|||
def self.append_features(base) | |||
setup(base) | |||
end | |||
|
|||
def self.caller_dir | |||
caller.each do |line| | |||
file = File.expand_path(line.split(':', 2).first) | |||
return File.dirname(file) if file != File.expand_path(__FILE__) | |||
end | |||
File.dirname($0) | |||
end | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,33 @@ | |||
module Tool | |||
module Lock | |||
if defined? Rubinius | |||
def synchronize | |||
Rubinius.synchronize(self) { yield } | |||
end | |||
else | |||
require 'thread' | |||
@lock = Mutex.new | |||
|
|||
def self.synchronize(&block) | |||
@lock.synchronize(&block) | |||
end | |||
|
|||
def synchronize(&block) | |||
Lock.synchronize { @lock, @locked_by = Mutex.new, nil unless lock? } unless lock? | |||
return yield if @locked_by == Thread.current | |||
@lock.synchronize do | |||
@locked_by = Thread.current | |||
result = yield | |||
@locked_by = nil | |||
result | |||
end | |||
end | |||
|
|||
private | |||
|
|||
def lock? | |||
instance_variable_defined? :@lock | |||
end | |||
end | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,3 @@ | |||
module Tool | |||
VERSION = '0.1.0' | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,6 @@ | |||
module Autoloader | |||
module Foo | |||
Answer = 42 | |||
include Tool::Autoloader | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,3 @@ | |||
module Autoloader::Foo | |||
Answer = 23 | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,2 @@ | |||
class Autoloader::Foo::Bar | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,2 @@ | |||
class Autoloader::Foo::Baz::Bar | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,2 @@ | |||
module Autoloader::Foo::Baz::Foo | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,2 @@ | |||
class Autoloader::Foo::Blah | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,2 @@ | |||
class Autoloader::Foo::Blah::Boom | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,2 @@ | |||
class Autoloader::Foo::CLI | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,2 @@ | |||
class Autoloader::Foo::FooBar | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,3 @@ | |||
module Autoloader::Foo | |||
VERSION = 1337 | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,47 @@ | |||
require 'tool' | |||
require 'autoloader/foo' | |||
|
|||
describe Tool::Autoloader do | |||
# poor man's matchers | |||
def autoload(const) be_autoload(const) end | |||
def start_with(str) be_start_with(str) end | |||
|
|||
it 'sets up autoloading' do | |||
Autoloader::Foo.should autoload(:Bar) | |||
Autoloader::Foo::Bar.name.should start_with("Autoloader::Foo::") | |||
end | |||
|
|||
it 'creates modules for subdirectories' do | |||
Autoloader::Foo.should_not autoload(:Baz) | |||
Autoloader::Foo::Baz.should autoload(:Bar) | |||
end | |||
|
|||
it 'handles nested constants with same name' do | |||
Autoloader::Foo::Baz::Foo.should_not be == Autoloader::Foo | |||
end | |||
|
|||
it 'does not automatically set up autoloading for autoloaded constants' do | |||
Autoloader::Foo::Blah.should_not autoload(:Boom) | |||
expect { Autoloader::Foo::Blah::Boom }.to raise_error(NameError) | |||
end | |||
|
|||
it 'does not override existing constants' do | |||
Autoloader::Foo::Answer.should be == 42 | |||
end | |||
|
|||
it 'loads VERSION' do | |||
Autoloader::Foo.should autoload(:VERSION) | |||
Autoloader::Foo.should_not autoload(:Version) | |||
Autoloader::Foo::VERSION.should be == 1337 | |||
end | |||
|
|||
it 'loads CLI' do | |||
Autoloader::Foo.should autoload(:CLI) | |||
Autoloader::Foo.should_not autoload(:Cli) | |||
end | |||
|
|||
it 'loads camel-cased constants' do | |||
Autoloader::Foo.should autoload(:FooBar) | |||
Autoloader::Foo.should_not autoload(:Foo_bar) | |||
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,43 @@ | |||
require 'tool' | |||
|
|||
describe Tool::Lock do | |||
before do | |||
Thread.abort_on_exception = true | |||
end | |||
|
|||
let(:object) { Object.new.extend(Tool::Lock) } | |||
let(:track) { [] } | |||
|
|||
def synchronize(&block) | |||
object.synchronize(&block) | |||
end | |||
|
|||
it 'runs the given block' do | |||
synchronize { track << :ran } | |||
track.should be == [:ran] | |||
end | |||
|
|||
it 'locks for other threads' do | |||
a = Thread.new { synchronize { sleep(0.1) and track << :first } } | |||
b = Thread.new { synchronize { track << :second } } | |||
|
|||
a.join | |||
b.join | |||
|
|||
track.should be == [:first, :second] | |||
end | |||
|
|||
it 'is no global lock' do | |||
a = Thread.new { Object.new.extend(Tool::Lock).synchronize { sleep(0.1) and track << :first } } | |||
b = Thread.new { Object.new.extend(Tool::Lock).synchronize { track << :second } } | |||
|
|||
a.join | |||
b.join | |||
|
|||
track.should be == [:second, :first] | |||
end | |||
|
|||
it 'has no issue with recursion' do | |||
synchronize { synchronize { } } | |||
end | |||
end |
Oops, something went wrong.