Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
fredwu committed Sep 11, 2012
0 parents commit 870c710
Show file tree
Hide file tree
Showing 12 changed files with 280 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
@@ -0,0 +1,17 @@
*.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
3 changes: 3 additions & 0 deletions Gemfile
@@ -0,0 +1,3 @@
source 'https://rubygems.org'

gemspec
29 changes: 29 additions & 0 deletions README.md
@@ -0,0 +1,29 @@
# Ruby Decorators

#### Ruby method decorators inspired by Python.

## Installation

Add this line to your application's Gemfile:

gem 'ruby_decorators'

And then execute:

$ bundle

Or install it yourself as:

$ gem install ruby_decorators

## Usage

```ruby
# TODO
```

## License

Copyright (c) 2012 [Fred Wu](http://fredwu.me/)

Licensed under the [MIT license](http://fredwu.mit-license.org/).
12 changes: 12 additions & 0 deletions Rakefile
@@ -0,0 +1,12 @@
require "bundler/gem_tasks"

require 'rake/testtask'


Rake::TestTask.new do |t|
t.libs.push 'lib'
t.test_files = FileList['spec/**/*_spec.rb']
t.verbose = true
end

task :default => :test
9 changes: 9 additions & 0 deletions lib/ruby_decorator.rb
@@ -0,0 +1,9 @@
class RubyDecorator
def self.+@
RubyDecorators::Stack.decorators << self
end

def +@
RubyDecorators::Stack.decorators << self
end
end
49 changes: 49 additions & 0 deletions lib/ruby_decorators.rb
@@ -0,0 +1,49 @@
require "ruby_decorators/version"
require "ruby_decorator"
require "ruby_decorators/stack"

module RubyDecorators
def method_added(method_name)
@decorated_methods ||= []

return if RubyDecorators::Stack.decorators.empty? ||
method_name.to_s =~ /__undecorated_/ ||
@decorated_methods.include?(method_name)

current_decorator = RubyDecorators::Stack.decorators.pop
method_visibility = detect_method_visibility(method_name)

class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
alias_method :__undecorated_#{method_name}, :#{method_name}
@__decorators ||= {}
@__decorators["#{method_name}"] = current_decorator
#{method_visibility}
def #{method_name}(*args, &blk)
decorator = #{current_decorator}.new
decorator ||= self.class.instance_variable_get(:@__decorators)["#{method_name}"]
if args.any?
decorator.call(self.send :__undecorated_#{method_name}, *args, &blk)
else
decorator.call(self.send :__undecorated_#{method_name}, &blk)
end
end
RUBY_EVAL

@decorated_methods << method_name
end

private

def detect_method_visibility(method_name)
if private_method_defined?(method_name)
:private
elsif protected_method_defined?(method_name)
:protected
else
:public
end
end
end
Binary file added lib/ruby_decorators/.DS_Store
Binary file not shown.
7 changes: 7 additions & 0 deletions lib/ruby_decorators/stack.rb
@@ -0,0 +1,7 @@
module RubyDecorators
class Stack
def self.decorators
@decorators ||= []
end
end
end
3 changes: 3 additions & 0 deletions lib/ruby_decorators/version.rb
@@ -0,0 +1,3 @@
module RubyDecorators
VERSION = "0.0.1"
end
23 changes: 23 additions & 0 deletions ruby_decorators.gemspec
@@ -0,0 +1,23 @@
# -*- encoding: utf-8 -*-
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'ruby_decorators/version'

Gem::Specification.new do |gem|
gem.name = "ruby_decorators"
gem.version = RubyDecorators::VERSION
gem.authors = ["Fred Wu"]
gem.email = ["ifredwu@gmail.com"]
gem.description = %q{Ruby method decorators inspired by Python.}
gem.summary = gem.description
gem.homepage = ""

gem.files = `git ls-files`.split($/)
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.require_paths = ["lib"]

gem.add_development_dependency 'rake'
gem.add_development_dependency 'pry'
gem.add_development_dependency 'minitest'
end
123 changes: 123 additions & 0 deletions spec/ruby_decorators_spec.rb
@@ -0,0 +1,123 @@
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')

describe RubyDecorators do
class DummyDecorator < RubyDecorator
def call(this)
'I should never be called'
end
end

class Batman < RubyDecorator
def call(this)
this.sub('world', 'batman')
end
end

class Catwoman < RubyDecorator
def initialize(*args)
@args = args.any? ? args : ['catwoman']
end

def call(this)
this.sub('world', @args.join(' '))
end
end

class DummyClass
extend RubyDecorators

attr_reader :greeting

def initialize
@greeting = 'hello world'
end

def hello_world
@greeting
end

+Batman
def hello_public
@greeting
end

+DummyDecorator
def hello_void
@greeting
end

+Batman
def hello_with_args(arg1, arg2)
"#{@greeting} #{arg1} #{arg2}"
end

+Catwoman
def hello_catwoman
@greeting
end

+Batman
def hello_with_block(arg1, arg2, &block)
"#{@greeting} #{arg1} #{arg2} #{block.call if block_given?}"
end

+Catwoman.new('super', 'catwoman')
def hello_super_catwoman
@greeting
end

protected

+Batman
def hello_protected
@greeting
end

private

+Batman
def hello_private
@greeting
end
end

subject { DummyClass.new }

it "#hello_world" do
subject.hello_world.must_equal 'hello world'
end

describe "a simple decorator" do
it "decorates a public method" do
subject.hello_public.must_equal 'hello batman'
end

it "decorates a protected method" do
subject.send(:hello_protected).must_equal 'hello batman'
lambda { subject.hello_protected }.must_raise NoMethodError
end

it "decorates a private method" do
subject.send(:hello_private).must_equal 'hello batman'
lambda { subject.hello_private }.must_raise NoMethodError
end

it "decorates a method with args" do
subject.hello_with_args('how are', 'you?').must_equal 'hello batman how are you?'
end

it "decorates a method with a block" do
subject.hello_with_block('how are', 'you') { 'man?' }.must_equal 'hello batman how are you man?'
end
end

describe "a decorator with args" do
it "decorates without any decorator args" do
subject.hello_catwoman.must_equal 'hello catwoman'
end

it "decorate a simple method" do
subject.hello_super_catwoman.must_equal 'hello super catwoman'
end
end
end
5 changes: 5 additions & 0 deletions spec/spec_helper.rb
@@ -0,0 +1,5 @@
require 'minitest/autorun'
require 'minitest/spec'
require 'pry'

require File.expand_path('../../lib/ruby_decorators', __FILE__)

0 comments on commit 870c710

Please sign in to comment.