module_chain_method 0.1.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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Kurt Stephens
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,73 @@
1
+ = module_chain_method
2
+
3
+ Module::ChainMethod mixin to simplify method chain aliasing.
4
+
5
+ == Example
6
+
7
+ require 'module/chain_method' # Module::ChainMethod
8
+
9
+ module MyMixin
10
+ def self.included target
11
+ super
12
+ $stderr.puts "MyMixin.included #{target}
13
+ end
14
+ include ::Module::ChainMethod
15
+
16
+ def foo
17
+ puts "MyMixin#foo"
18
+ foo_without_MyMixin
19
+ end
20
+
21
+ def bar
22
+ puts "MyMixin#bar"
23
+ end
24
+
25
+ # Prepares method #foo for chaining.
26
+ chain_method :foo
27
+ end
28
+
29
+ class Foo
30
+ def foo
31
+ puts "Foo#foo"
32
+ end
33
+
34
+ def bar
35
+ puts "Foo#bar"
36
+ super rescue nil
37
+ end
38
+ end
39
+
40
+ f = Foo.new
41
+ f.foo
42
+ f.bar
43
+ puts
44
+
45
+ Foo.send(:include, MyMixin)
46
+ f.foo
47
+ f.bar
48
+
49
+ Generates the following output:
50
+
51
+ > ruby -I lib example/ex01.rb
52
+ Foo#foo
53
+ Foo#bar
54
+
55
+ MyMixin.included Foo
56
+ MyMixin#foo
57
+ Foo#foo
58
+ Foo#bar
59
+ MyMixin#bar
60
+
61
+ == Note on Patches/Pull Requests
62
+
63
+ * Fork the project.
64
+ * Make your feature addition or bug fix.
65
+ * Add tests for it. This is important so I don't break it in a
66
+ future version unintentionally.
67
+ * Commit, do not mess with rakefile, version, or history.
68
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
69
+ * Send me a pull request. Bonus points for topic branches.
70
+
71
+ == Copyright
72
+
73
+ Copyright (c) 2010 Kurt Stephens. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "module_chain_method"
8
+ gem.summary = %Q{Module::ChainMethod mixin to simplify method chain aliasing.}
9
+ gem.description = %Q{Module::ChainMethod mixin to simplify method chain aliasing.}
10
+ gem.email = "ks.github@kurtstephens.com"
11
+ gem.homepage = "http://github.com/kstephens/module_chain_method"
12
+ gem.authors = ["Kurt Stephens"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "module_chain_method #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/example/ex01.rb ADDED
@@ -0,0 +1,40 @@
1
+ require 'module/chain_method' # Module::ChainMethod
2
+
3
+ module MyMixin
4
+ def self.included target
5
+ super
6
+ $stderr.puts "MyMixin.included #{target}"
7
+ end
8
+ include ::Module::ChainMethod
9
+
10
+ def foo
11
+ puts "MyMixin#foo"
12
+ foo_without_MyMixin
13
+ end
14
+ # Prepares method #foo for chaining.
15
+ chain_method :foo
16
+
17
+ def bar
18
+ puts "MyMixin#bar"
19
+ end
20
+ end
21
+
22
+ class Foo
23
+ def foo
24
+ puts "Foo#foo"
25
+ end
26
+
27
+ def bar
28
+ puts "Foo#bar"
29
+ super rescue nil
30
+ end
31
+ end
32
+
33
+ f = Foo.new
34
+ f.foo
35
+ f.bar
36
+ puts
37
+
38
+ Foo.send(:include, MyMixin)
39
+ f.foo
40
+ f.bar
@@ -0,0 +1,96 @@
1
+
2
+ class Module
3
+ module ChainMethod
4
+ def self.included target
5
+ # $stderr.puts "ChainMethod #{self.inspect}.included #{target}"
6
+ super
7
+ target.extend(ClassMethods) if Class === target
8
+ target.extend(ModuleMethods) if Module === target
9
+ if target.method_defined?(:included)
10
+ target.send(:alias_method, :included_without_ChainMethod, :included)
11
+ end
12
+ end
13
+
14
+ module ModuleMethods
15
+ def included target
16
+ # $stderr.puts "ChainMethod::ModuleMethods #{self.inspect}.included #{target}"
17
+ super
18
+ self.included_without_ChainMethod(target) if self.respond_to?(:included_without_ChainMethod)
19
+ # $stderr.puts "#{target.inspect}.ancestors = #{target.ancestors.inspect}"
20
+ target.extend(self.ClassMethods) if Class === target && defined?(self.ClassMethod)
21
+ target.extend(self.ModuleMethods) if Module === target && defined?(self.ModuleMethods)
22
+ chain_methods! target
23
+ end
24
+
25
+ def chain_methods suffix = nil
26
+ # $stderr.puts "ChainMethod::ModuleMethods #{self.inspect}.chain_methods #{suffix.inspect}"
27
+ @chain_methods_suffix = suffix if suffix
28
+ @chain_methods ||= [ ]
29
+ end
30
+
31
+ def _chain_methods_suffix
32
+ @chain_methods_suffix ||= self.name.sub(/.*::/, '').freeze
33
+ @_chain_methods_suffix ||= @chain_methods_suffix.to_s.sub(/[^a-z0-9_]/i, '_').freeze
34
+ end
35
+
36
+ def chain_method *selectors
37
+ # $stderr.puts "ChainMethod::ModuleMethods #{self.inspect}.chain_method #{selectors.inspect}"
38
+ chain_methods.push(*selectors.map{|m| m.to_sym}).uniq!
39
+ # $stderr.puts "chain_selectors = #{chain_methods.inspect}"
40
+ self
41
+ end
42
+
43
+ # NOT THREAD-SAFE!
44
+ def prepare_methods!
45
+ @chain_methods_prepared ||= [ ]
46
+ # $stderr.puts "ChainMethod::ModuleMethods #{self.inspect}.prepare_methods!"
47
+
48
+ suffix = _chain_methods_suffix
49
+
50
+ target = self
51
+
52
+ # $stderr.puts " BEFORE: #{(target.instance_methods.sort - Object.methods).inspect}"
53
+
54
+ chain_methods.each do | selector |
55
+ next if @chain_methods_prepared.include?(selector)
56
+ @chain_methods_prepared << selector
57
+
58
+ without_selector = _map_selector(selector, "_without_#{suffix}")
59
+ with_selector = _map_selector(selector, "_with_#{suffix}")
60
+ # $stderr.puts " #{target.inspect}.alias #{without_selector.inspect} #{selector.inspect}"
61
+ unless target.method_defined?(with_selector)
62
+ target.send(:alias_method, with_selector, selector)
63
+ end
64
+ end
65
+ # $stderr.puts " AFTER: #{(target.instance_methods.sort - Object.methods).inspect}"
66
+
67
+ self
68
+ end
69
+
70
+ def chain_methods! target
71
+ # $stderr.puts "ChainMethod::ModuleMethods #{self.inspect}.chain_methods! #{target.inspect}"
72
+ prepare_methods!
73
+ suffix = _chain_methods_suffix
74
+
75
+ # $stderr.puts " BEFORE: #{(target.instance_methods.sort - Object.methods).inspect}"
76
+ chain_methods.each do | selector |
77
+ without_selector = _map_selector(selector, "_without_#{suffix}")
78
+ with_selector = _map_selector(selector, "_with_#{suffix}")
79
+ # $stderr.puts " #{target.inspect}.alias #{without_selector.inspect} #{selector.inspect}"
80
+ unless target.method_defined?(without_selector)
81
+ target.send(:alias_method, without_selector, selector)
82
+ end
83
+ target.send(:alias_method, selector, with_selector)
84
+ end
85
+ # $stderr.puts " AFTER: #{(target.instance_methods.sort - Object.methods).inspect}"
86
+ end
87
+
88
+ def _map_selector selector, suffix
89
+ selector.to_s.
90
+ sub(/\A([a-z0-9_]+)([^a-z0-9_]?)\Z/i) { | m | $1 + suffix + $2 }.
91
+ to_sym
92
+ end
93
+ end
94
+ end
95
+ end
96
+
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'module/chain_method'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,72 @@
1
+ require 'helper'
2
+
3
+ require 'module/chain_method'
4
+
5
+ class TestModuleChainMethod < Test::Unit::TestCase
6
+ should "handle Foo#foo and Foo#bar as expected" do
7
+ f = Module::ChainMethod::Test::Foo.new
8
+ f.foo
9
+ f.bar
10
+ assert_equal(f.instance_variable_get("@calls"), [ "Foo#foo", "Foo#bar" ])
11
+ end
12
+
13
+ should "handle Foo#foo and Foo#bar with aliases for *_without_MyMixin" do
14
+ Module::ChainMethod::Test::Foo.class_eval do
15
+ include Module::ChainMethod::Test::MyMixin
16
+ end
17
+ assert_equal(
18
+ [ "MyMixin.included Module::ChainMethod::Test::Foo" ],
19
+ Module::ChainMethod::Test::MyMixin.instance_variable_get("@calls")
20
+ )
21
+
22
+ f = Module::ChainMethod::Test::Foo.new
23
+ f.foo
24
+ f.bar
25
+ assert_equal(
26
+ [ "MyMixin#foo", "Foo#foo", "Foo#bar" ],
27
+ f.instance_variable_get("@calls")
28
+ )
29
+
30
+ end
31
+ end
32
+
33
+
34
+ ######################################################################
35
+
36
+
37
+ class Module
38
+ module ChainMethod
39
+ module Test
40
+ module MyMixin
41
+ def self.included target
42
+ super
43
+ (@calls ||= [ ]) << "MyMixin.included #{target.inspect}"
44
+ end
45
+ include ::Module::ChainMethod
46
+
47
+ def foo
48
+ (@calls ||= [ ]) << "MyMixin#foo"
49
+ foo_without_MyMixin
50
+ end
51
+
52
+ def bar
53
+ (@calls ||= [ ]) << "MyMixin#bar"
54
+ end
55
+
56
+ chain_method :foo
57
+ end
58
+
59
+ class Foo
60
+ def foo
61
+ (@calls ||= [ ]) << "Foo#foo"
62
+ end
63
+
64
+ def bar
65
+ (@calls ||= [ ]) << "Foo#bar"
66
+ end
67
+ end
68
+
69
+ end
70
+ end
71
+ end
72
+
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: module_chain_method
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Kurt Stephens
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-03 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: thoughtbot-shoulda
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ description: Module::ChainMethod mixin to simplify method chain aliasing.
36
+ email: ks.github@kurtstephens.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.rdoc
44
+ files:
45
+ - .document
46
+ - .gitignore
47
+ - LICENSE
48
+ - README.rdoc
49
+ - Rakefile
50
+ - VERSION
51
+ - example/ex01.rb
52
+ - lib/module/chain_method.rb
53
+ - test/helper.rb
54
+ - test/test_module_chain_method.rb
55
+ has_rdoc: true
56
+ homepage: http://github.com/kstephens/module_chain_method
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options:
61
+ - --charset=UTF-8
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 3
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ requirements: []
83
+
84
+ rubyforge_project:
85
+ rubygems_version: 1.3.7
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Module::ChainMethod mixin to simplify method chain aliasing.
89
+ test_files:
90
+ - test/helper.rb
91
+ - test/test_module_chain_method.rb