meta_programming 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ .DS_Store
2
+ pkg
3
+ nbproject
4
+ TODO.txt
5
+ *.gemspec
6
+ *.gem
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006-2009 Jeff Patmon
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,28 @@
1
+ = MetaProgramming
2
+
3
+ Various meta-programming methods and 'spells' for Ruby
4
+
5
+ == Resources
6
+
7
+ Install
8
+
9
+ * sudo gem install meta_programming
10
+
11
+ Use
12
+
13
+ * require 'meta_programming'
14
+
15
+
16
+ == Description
17
+
18
+ Current Methods
19
+ * eigenclass (or metaclass)
20
+ * safe_alias_method_chain
21
+ * define_chained_method
22
+ * blank_slate
23
+ * clean_room
24
+
25
+
26
+ == Dependencies
27
+
28
+ none
data/Rakefile ADDED
@@ -0,0 +1,66 @@
1
+ #require 'rake/testtask'
2
+ require 'rake/rdoctask'
3
+ require 'rake/gempackagetask'
4
+ gem 'gem_version', '>= 0.0.1'
5
+ require 'gem_version'
6
+ #require 'rake/contrib/sshpublisher'
7
+
8
+ spec = Gem::Specification.new do |s|
9
+ s.name = 'meta_programming'
10
+ s.version = GemVersion.next_version
11
+ s.platform = Gem::Platform::RUBY
12
+ s.required_ruby_version = '>= 1.8.7'
13
+ s.description = 'Collection of meta-programming methods for Ruby'
14
+ s.summary = 'Collection of meta-programming methods for Ruby'
15
+
16
+
17
+ exclude_folders = '' # 'spec/rails/{doc,lib,log,nbproject,tmp,vendor,test}'
18
+ exclude_files = [] # FileList['**/*.log'] + FileList[exclude_folders+'/**/*'] + FileList[exclude_folders]
19
+ s.files = FileList['{lib,spec}/**/*'] + %w(init.rb LICENSE Rakefile README.rdoc .gitignore) - exclude_files
20
+ s.require_path = 'lib'
21
+ s.has_rdoc = true
22
+ s.test_files = Dir['spec/*_spec.rb']
23
+
24
+ s.author = 'Jeff Patmon'
25
+ s.email = 'jpatmon@gmail.com'
26
+ s.homepage = 'http://github.com/jeffp/meta_programming/tree/master'
27
+ end
28
+
29
+ require 'spec/version'
30
+ require 'spec/rake/spectask'
31
+
32
+ desc "Run specs"
33
+ Spec::Rake::SpecTask.new(:spec) do |t|
34
+ t.spec_files = FileList['spec/*_spec.rb']
35
+ t.libs << 'lib' << 'spec'
36
+ t.rcov = false
37
+ t.spec_opts = ['--options', 'spec/spec.opts']
38
+ #t.rcov_dir = 'coverage'
39
+ #t.rcov_opts = ['--exclude', "kernel,load-diff-lcs\.rb,instance_exec\.rb,lib/spec.rb,lib/spec/runner.rb,^spec/*,bin/spec,examples,/gems,/Library/Ruby,\.autotest,#{ENV['GEM_HOME']}"]
40
+ end
41
+
42
+ desc "Generate documentation for the #{spec.name} gem."
43
+ Rake::RDocTask.new(:rdoc) do |rdoc|
44
+ rdoc.rdoc_dir = 'rdoc'
45
+ rdoc.title = spec.name
46
+ #rdoc.template = '../rdoc_template.rb'
47
+ rdoc.options << '--line-numbers' << '--inline-source'
48
+ rdoc.rdoc_files.include('README.rdoc', 'LICENSE', 'lib/**/*.rb')
49
+ end
50
+
51
+ desc 'Generate a gemspec file.'
52
+ task :gemspec do
53
+ File.open("#{spec.name}.gemspec", 'w') do |f|
54
+ f.write spec.to_ruby
55
+ end
56
+ GemVersion.increment_version
57
+ GemVersion.commit_and_push
58
+ end
59
+
60
+ Rake::GemPackageTask.new(spec) do |p|
61
+ p.gem_spec = spec
62
+ p.need_tar = RUBY_PLATFORM =~ /mswin/ ? false : true
63
+ p.need_zip = true
64
+ end
65
+
66
+ Dir['tasks/**/*.rake'].each {|rake| load rake}
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'arspy'
@@ -0,0 +1,8 @@
1
+ require 'meta_programming/object'
2
+ require 'meta_programming/class'
3
+
4
+ module MetaProgramming
5
+ end
6
+
7
+ Object.send :include, MetaProgramming::Object
8
+ Class.send :include, MetaProgramming::Class
@@ -0,0 +1,17 @@
1
+ module MetaProgramming
2
+ module Class
3
+ def self.included(base)
4
+ raise 'This module may only be included in class Class' unless base.name == 'Class'
5
+ end
6
+
7
+ def blank_slate(opts={})
8
+ opts[:except] = opts[:except] ? (opts[:except].is_a?(Array) ? opts[:except] : [opts[:except]]) : []
9
+ exceptions = ['method_missing', 'respond_to\?', '^__'] + opts[:except].map{|ex| ex.to_s}
10
+ regexp = Regexp.new(exceptions.join('|'))
11
+ instance_methods.each do |m|
12
+ undef_method m unless regexp.match(m.to_s)
13
+ end
14
+ end
15
+ alias_method :clean_room, :blank_slate
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ module MetaProgramming
2
+ module Object
3
+ def self.included(base)
4
+ raise 'This module may only be included in class Object' unless base.name == 'Object'
5
+ base.extend(ClassMethods)
6
+ base.class_eval do
7
+ alias_method :metaclass, :eigenclass
8
+ end
9
+ end
10
+
11
+ def eigenclass
12
+ class << self; self; end
13
+ end
14
+
15
+ module ClassMethods
16
+ def safe_alias_method_chain(method_name, ext)
17
+ class_eval do
18
+ stripped_method_name, punctuation = method_name.to_s.sub(/([?!=])$/, ''), $1
19
+ method_name_with_ext = "#{stripped_method_name}_with_#{ext}#{punctuation}".to_sym
20
+ method_name_without_ext = "#{stripped_method_name}_without_#{ext}#{punctuation}".to_sym
21
+ instance_variable = "#{stripped_method_name}_#{ext}_#{{'?'=>'questmark', '!'=>'bang', '='=>'equals'}[punctuation]}"
22
+ if (method_defined?(method_name_with_ext) && !(eigenclass.instance_variable_defined?("@#{instance_variable}")))
23
+ if method_defined?(method_name.to_sym)
24
+ #alias_method_chain(method_name.to_sym, ext.to_sym)
25
+ alias_method method_name_without_ext, method_name.to_sym
26
+ alias_method method_name.to_sym, method_name_with_ext
27
+ case
28
+ when public_method_defined?(method_name_without_ext) then public(method_name.to_sym)
29
+ when protected_method_defined?(method_name_without_ext) then protected(without_method.to_sym)
30
+ when private_method_defined?(method_name_without_ext) then private(without_method.to_sym)
31
+ end
32
+ else
33
+ alias_method method_name.to_sym, method_name_with_ext
34
+ define_method(method_name_without_ext) {|*args| }
35
+ end
36
+ eigenclass.instance_variable_set("@#{instance_variable}", true)
37
+ end
38
+ end
39
+ end
40
+
41
+ def define_chained_method(method_name, ext, &block)
42
+ define_method("#{method_name}_with_#{ext}".to_sym, block)
43
+ safe_alias_method_chain(method_name.to_sym, ext)
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,159 @@
1
+ require 'lib/meta_programming'
2
+
3
+ describe "MetaProgramming" do
4
+ describe "eigenclass and metaclass methods" do
5
+ it "should return the eigen class of a class" do
6
+ class A
7
+ class << self; self; end.should == self.eigenclass
8
+ class << self; self; end.should == self.metaclass
9
+ end
10
+ class << A; self; end.should == A.eigenclass
11
+ class << A; self; end.should == A.metaclass
12
+ end
13
+ it "should return the eigen class of an object" do
14
+ class A; def return_eigenclass; eigenclass; end; end
15
+ a = A.new
16
+ class << a; self; end.should == a.eigenclass
17
+ class << a; self; end.should == a.metaclass
18
+ end
19
+ end
20
+ describe "define_chained_method" do
21
+ it "should complain if there is no block" do
22
+ lambda {
23
+ class B1
24
+ def target; end
25
+ define_chained_method(:target, :chain)
26
+ end
27
+ }.should raise_exception
28
+ end
29
+ it "should define and chain a method" do
30
+ class B2; def target(array); array << 'target'; end; end
31
+ B2.new.target(['init']).should == ['init', 'target']
32
+ class B2
33
+ define_chained_method(:target, :chain) do |array|
34
+ array << 'chain'
35
+ target_without_chain(array)
36
+ end
37
+ end
38
+ B2.new.target(['init']).should == ['init', 'chain', 'target']
39
+ end
40
+ # it "should complain if block has wrong arity" do
41
+ # lambda {
42
+ # class B3
43
+ # def target(array); array << 'target'; end
44
+ # define_chained_method(:target, :chain) do
45
+ # target_without_chain(['chain'])
46
+ # end
47
+ # end
48
+ # B3.new.target(['init'])
49
+ # }.should raise_exception
50
+ # end
51
+ it "should define and chain a method safely if there is no target method" do
52
+ class B4
53
+ define_chained_method(:target, :chain) do |array|
54
+ array << 'chain'
55
+ target_without_chain(array)
56
+ end
57
+ B4.new.target(['init']).should == ['init', 'chain']
58
+ end
59
+ end
60
+ end
61
+ describe "safe_alias_method_chain method" do
62
+ it "should not chain for non-existent chaining method" do
63
+ class A
64
+ def primary(array); array << 'primary'; end
65
+ #do not define :primary_with_ext
66
+ safe_alias_method_chain :primary, :ext
67
+ end
68
+ a=A.new
69
+ a.primary(['init']).should == ['init', 'primary']
70
+ end
71
+ it "should not raise NoMethod error when chaining for non-existing primary method" do
72
+ lambda {
73
+ class A0
74
+ def primary_with_ext(array)
75
+ array << 'chaining'
76
+ primary_without_ext(array)
77
+ end
78
+ safe_alias_method_chain :primary, :ext
79
+ end
80
+ a=A0.new
81
+ a.primary(['init']).should == ['init', 'chaining']
82
+ }.should_not raise_exception(NoMethodError)
83
+ end
84
+ it "should chain for two methods" do
85
+ class A1
86
+ def primary(array)
87
+ array << 'primary'
88
+ end
89
+
90
+ def primary_with_ext(array)
91
+ array << 'chaining_in'
92
+ primary_without_ext(array)
93
+ array << 'chaining_out'
94
+ end
95
+ safe_alias_method_chain :primary, :ext
96
+ end
97
+ A1.new.primary(['init']).should == ['init', 'chaining_in', 'primary', 'chaining_out']
98
+ end
99
+ it "should chain for three methods" do
100
+ class A2
101
+ def primary(array); array << 'primary'; end
102
+
103
+ def primary_with_one(array); array << 'one'; primary_without_one(array); end
104
+
105
+ def primary_with_two(array); array << 'two'; primary_without_two(array); end
106
+
107
+ safe_alias_method_chain :primary, :one
108
+ safe_alias_method_chain :primary, :two
109
+ end
110
+ A2.new.primary(['init']).should == ['init', 'two', 'one', 'primary']
111
+ end
112
+ it "should not cause endless loop when called twice" do
113
+ lambda {
114
+ class A3
115
+ def primary(array); array << 'primary'; end
116
+ def primary_with_one(array); array << 'one'; primary_without_one(array); end
117
+
118
+ safe_alias_method_chain :primary, :one
119
+ safe_alias_method_chain :primary, :one
120
+ end
121
+ A3.new.primary(['init']).should == ['init', 'one', 'primary']
122
+ }.should_not raise_exception
123
+ end
124
+ it "should chain with = punctuation" do
125
+ class A5
126
+ def primary=(array); array << 'primary'; end
127
+ def primary_with_one=(array); array << 'one'; self.primary_without_one=(array); end
128
+
129
+ safe_alias_method_chain :primary=, :one
130
+ end
131
+ lambda {
132
+ a = A5.new.primary=(['init'])
133
+ a.should == ['init', 'one', 'primary']
134
+ }.should_not raise_exception
135
+ end
136
+ it "should chain with ? punctuation" do
137
+ class A6
138
+ def primary?(array); array << 'primary'; end
139
+ def primary_with_one?(array); array << 'one'; primary_without_one?(array); end
140
+
141
+ safe_alias_method_chain :primary?, :one
142
+ end
143
+ lambda {
144
+ A6.new.primary?(['init']).should == ['init', 'one', 'primary']
145
+ }.should_not raise_exception
146
+ end
147
+ it "should chain with ! punctuation" do
148
+ class A7
149
+ def primary!(array); array << 'primary'; end
150
+ def primary_with_one!(array); array << 'one'; primary_without_one!(array); end
151
+
152
+ safe_alias_method_chain :primary!, :one
153
+ end
154
+ lambda {
155
+ A7.new.primary!(['init']).should == ['init', 'one', 'primary']
156
+ }.should_not raise_exception
157
+ end
158
+ end
159
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: meta_programming
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Jeff Patmon
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-29 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Collection of meta-programming methods for Ruby
22
+ email: jpatmon@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/meta_programming/class.rb
31
+ - lib/meta_programming/object.rb
32
+ - lib/meta_programming.rb
33
+ - spec/meta_programming_spec.rb
34
+ - spec/spec.opts
35
+ - init.rb
36
+ - LICENSE
37
+ - Rakefile
38
+ - README.rdoc
39
+ - .gitignore
40
+ has_rdoc: true
41
+ homepage: http://github.com/jeffp/meta_programming/tree/master
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 1
55
+ - 8
56
+ - 7
57
+ version: 1.8.7
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.3.6
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Collection of meta-programming methods for Ruby
72
+ test_files:
73
+ - spec/meta_programming_spec.rb