elliottcable-refinery 0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,126 @@
1
+ Refinery
2
+ ========
3
+ Refinery stemmed from a very specific need that arose while writing
4
+ [attr_*][] — to be able to utilize the Ruby hooks (for example, the
5
+ `method_added` and `method_missing` methods) without “gobbling them up” so to
6
+ speak. Normally, had I used those methods (especially if my particular
7
+ implementation was very dependent on these methods operating in a specific
8
+ way), the person using my library would be precluded from using the same
9
+ methods in whatever class they included/extended my library into; if they used
10
+ one of those methods for some purpose, their definition would ‘overwrite’ mine,
11
+ thus quite possibly making my library (or their code using my library) cease
12
+ to function correctly.
13
+
14
+ The simple, singular purpose of Refinery is to ‘refine’ methods in such a way
15
+ that your important functionality can be assigned safely to these methods.
16
+ Any attempts to re-define a ‘refined’ method after the refining process will
17
+ simply ‘stack’ with your own implementation — your method code will execute
18
+ first, with further re-definitions each being executed in turn when the method
19
+ is called.
20
+
21
+ [attr_*]: <http://by.elliottcable.name/attr_splat.xhtml> "elliottcable's attr_splat project"
22
+
23
+ Usage
24
+ -----
25
+ Using Refinery is very simple - extend it into your class (or include it into
26
+ the Class class if you use it often), and then pass a method's name (as a
27
+ symbol) to the refine_method singleton method. A short example:
28
+
29
+ class Something
30
+ extend Refinery
31
+
32
+ def method_missing meth, *args
33
+ # Do some magic!
34
+ puts 'abc'
35
+ end
36
+
37
+ refine_method :method_missing
38
+ end
39
+
40
+ # Later, somewhere else…
41
+
42
+ class Nothing < Something
43
+ def method_missing meth, *args
44
+ # Do other magic, not knowing about the former magic!
45
+ puts 'def'
46
+ end
47
+ end
48
+
49
+ nothing = Nothing.new
50
+ nothing.nonexistant_method
51
+
52
+ Once refined, any further re-openings of your class (or a descendant) and
53
+ re-definitions of the refined method will simply result in the implementations
54
+ 'stacking' with eachother.
55
+
56
+ Care must obviously still be taken to ensure your code will 'stack' in a
57
+ friendly way with the other implementations — be sure to programmatically
58
+ check whatever may be necessary before executing your method's code!
59
+
60
+ Installation
61
+ ------------
62
+ You can install Refinery as a pre-built gem, or as a gem generated directly
63
+ from the source.
64
+
65
+ The easiest way to install Refinery is to use [RubyGems][] to acquire the
66
+ latest 'release' version from [RubyForge][], using the `gem` command line tool:
67
+
68
+ sudo gem install refinery # You'll be asked for your account password.
69
+
70
+ Alternatively, you can acquire it (possibly slightly more up-to-date,
71
+ depending on how often I update the gemspec) from GitHub as follows:
72
+
73
+ # If you've ever done this before, you don't need to do it now - see http://gems.github.com
74
+ gem sources -a http://gems.github.com
75
+ sudo gem install elliottcable-refinery # You'll be asked for your account password.
76
+
77
+ Finally, you can build a gem from the latest source yourself. You need [git][],
78
+ as well as [rake][]:
79
+
80
+ git clone git://github.com/elliottcable/refinery.git
81
+ cd refinery
82
+ # If you've ever done this before, you don't need to do it now - see http://gems.github.com
83
+ gem sources -a http://gems.github.com
84
+ sudo gem install elliottcable-echoe # You'll be asked for your account password.
85
+ rake install # You'll be asked for your account password.
86
+
87
+ [RubyGems]: <http://rubyforge.org/projects/rubygems/> "RubyGems - Ruby package manager"
88
+ [RubyForge]: <http://rubyforge.org/projects/refinery/> "Refinery on RubyForge"
89
+ [git]: <http://git-scm.com/> "git - Fast Version Control System"
90
+
91
+ Contributing
92
+ ------------
93
+ You can contribute bug fixes or new features to Refinery by forking the project
94
+ on GitHub (you'll need to register for an account first), and sending me a
95
+ pull request once you've committed your changes.
96
+
97
+ Links
98
+ -----
99
+ - [GitHub](http://github.com/elliottcable/refinery "Refinery on GitHub") is the
100
+ project's primary repository host, and currently also the project's home
101
+ page
102
+ - [RubyForge](http://rubyforge.org/projects/refinery "Refinery on RubyForge") is
103
+ out primary RubyGem host, as well as an alternative repository host
104
+ - [integrity](http://integrit.yreality.net/refinery "Refinery on yreality's integrity server")
105
+ is out continuous integration server - if the top build on that page is
106
+ green, you can assume the latest git HEAD is safe to run/install/utilize.
107
+ - [Gitorious](http://gitorious.org/projects/refinery "Refinery on Gitorious") is
108
+ an alternative repository host
109
+ - [repo.or.cz](http://repo.or.cz/w/refinery.git "Refinery on repo.or.cz") is
110
+ an alternative repository host
111
+
112
+ Attribution
113
+ -----------
114
+ The Sing extension was contributed by [John Mair][banisterfiend].
115
+
116
+ [banisterfiend]: <http://banisterfiend.wordpress.com/> "Banisterfiend (John Mair)'s Weblog"
117
+
118
+ License
119
+ -------
120
+ Refinery is copyright 2008 by elliott cable.
121
+
122
+ Refinery is released under the [GNU General Public License v3.0][gpl], which
123
+ allows you to freely utilize, modify, and distribute all Refinery's source code
124
+ (subject to the terms of the aforementioned license).
125
+
126
+ [gpl]: <http://www.gnu.org/licenses/gpl.txt> "The GNU General Public License v3.0"
@@ -0,0 +1,134 @@
1
+ ($:.unshift File.expand_path(File.join( File.dirname(__FILE__), 'lib' ))).uniq!
2
+ begin
3
+ require 'refinery'
4
+ rescue LoadError
5
+ module Refinery; Version = -1; end
6
+ end
7
+
8
+ # =======================
9
+ # = Gem packaging tasks =
10
+ # =======================
11
+ begin
12
+ require 'echoe'
13
+
14
+ task :package => :'package:install'
15
+ task :manifest => :'package:manifest'
16
+ namespace :package do
17
+ Echoe.new('refinery', Refinery::Version) do |g|; g.name = 'Refinery'
18
+ g.project = 'refinery'
19
+ g.author = ['elliottcable']
20
+ g.email = ['Refinery@elliottcable.com']
21
+ g.summary = 'Mmmmagic'
22
+ g.url = 'http://github.com/elliottcable/refinery'
23
+ g.development_dependencies = ['elliottcable-echoe >= 3.0.2', 'rspec', 'rcov', 'yard', 'stringray']
24
+ g.manifest_name = '.manifest'
25
+ g.retain_gemspec = true
26
+ g.rakefile_name = 'Rakefile.rb'
27
+ g.ignore_pattern = /^\.git\/|^meta\/|\.gemspec/
28
+ end
29
+
30
+ desc 'tests packaged files to ensure they are all present'
31
+ task :verify => :package do
32
+ # An error message will be displayed if files are missing
33
+ if system %(ruby -e "require 'rubygems'; require 'pkg/refinery-#{Refinery::Version}/lib/refinery'")
34
+ puts "\nThe library files are present"
35
+ end
36
+ end
37
+ end
38
+
39
+ rescue LoadError
40
+ desc 'You need the `elliottcable-echoe` gem to package Refinery'
41
+ task :package
42
+ end
43
+
44
+ # =======================
45
+ # = Spec/Coverage tasks =
46
+ # =======================
47
+ begin
48
+ require 'spec'
49
+ require 'rcov'
50
+ require 'spec/rake/spectask'
51
+
52
+ task :default => :'coverage:run'
53
+ task :coverage => :'coverage:run'
54
+ namespace :coverage do
55
+ Spec::Rake::SpecTask.new(:run) do |t|
56
+ t.spec_opts = ["--format", "specdoc"]
57
+ t.spec_opts << "--colour" unless ENV['CI']
58
+ t.spec_files = Dir['spec/**/*_spec.rb'].sort
59
+ t.libs = ['lib']
60
+ t.rcov = true
61
+ t.rcov_opts = [ '--include-file', '"^lib"', '--exclude-only', '".*"']
62
+ t.rcov_dir = File.join('meta', 'coverage')
63
+ end
64
+
65
+ begin
66
+ require 'spec/rake/verify_rcov'
67
+ # For the moment, this is the only way I know of to fix RCov. I may
68
+ # release the fix as it's own gem at some point in the near future.
69
+ require 'stringray/core_ext/spec/rake/verify_rcov'
70
+ RCov::VerifyTask.new(:verify) do |t|
71
+ t.threshold = 95.0
72
+ t.index_html = File.join('meta', 'coverage', 'index.html')
73
+ t.require_exact_threshold = false
74
+ end
75
+ rescue LoadError
76
+ desc 'You need the `stringray` gem to verify coverage'
77
+ task :verify
78
+ end
79
+
80
+ task :open do
81
+ system 'open ' + File.join('meta', 'coverage', 'index.html') if PLATFORM['darwin']
82
+ end
83
+ end
84
+
85
+ rescue LoadError
86
+ desc 'You need the `rcov` and `rspec` gems to run specs/coverage'
87
+ task :coverage
88
+ end
89
+
90
+ # =======================
91
+ # = Documentation tasks =
92
+ # =======================
93
+ begin
94
+ require 'yard'
95
+ require 'yard/rake/yardoc_task'
96
+
97
+ task :documentation => :'documentation:generate'
98
+ namespace :documentation do
99
+ YARD::Rake::YardocTask.new :generate do |t|
100
+ t.files = ['lib/**/*.rb']
101
+ t.options = ['--output-dir', File.join('meta', 'documentation'),
102
+ '--readme', 'README.markdown']
103
+ end
104
+
105
+ YARD::Rake::YardocTask.new :dotyardoc do |t|
106
+ t.files = ['lib/**/*.rb']
107
+ t.options = ['--no-output',
108
+ '--readme', 'README.markdown']
109
+ end
110
+
111
+ task :open do
112
+ system 'open ' + File.join('meta', 'documentation', 'index.html') if PLATFORM['darwin']
113
+ end
114
+ end
115
+
116
+ rescue LoadError
117
+ desc 'You need the `yard` gem to generate documentation'
118
+ task :documentation
119
+ end
120
+
121
+ # =========
122
+ # = Other =
123
+ # =========
124
+ desc 'Removes all meta producs'
125
+ task :clobber do
126
+ `rm -rf #{File.expand_path(File.join( File.dirname(__FILE__), 'meta' ))}`
127
+ end
128
+
129
+ desc 'Check everything over before commiting'
130
+ task :aok => [:'documentation:generate', :'documentation:open',
131
+ :'package:manifest', :'package:package', :'package:compile',
132
+ :'coverage:run', :'coverage:open', :'coverage:verify']
133
+
134
+ task :ci => [:'documentation:generate', :'coverage:run', :'coverage:verify']
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile("sing")
@@ -0,0 +1,13 @@
1
+ #include <ruby.h>
2
+ #include <stdio.h>
3
+
4
+ VALUE jm_Module;
5
+ VALUE singleton(VALUE self) {
6
+ if(FL_TEST(self, FL_SINGLETON)) return Qtrue;
7
+ else return Qfalse;
8
+ }
9
+
10
+ void Init_sing() {
11
+ jm_Module = rb_define_module("Sing");
12
+ rb_define_method(jm_Module,"singleton?",singleton,0);
13
+ }
@@ -0,0 +1,10 @@
1
+ require 'refinery/core_ext/class'
2
+
3
+ module Refinery
4
+ Version = 0
5
+
6
+ # This refines an instance method named 'meth'.
7
+ def refine_method meth
8
+
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ require 'sing'
2
+
3
+ class Class
4
+ # Pulls in #singleton?
5
+ include Sing
6
+
7
+ ##
8
+ # Returns a list of all instances of this class
9
+ def instances
10
+ ObjectSpace.each_object(self).to_a
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ class Object
2
+ ##
3
+ # Returns the singleton class for this object.
4
+ def singleton
5
+ class<<self;self;end
6
+ end
7
+ end
@@ -0,0 +1,128 @@
1
+
2
+ # Gem::Specification for Refinery-0
3
+ # Originally generated by Echoe
4
+
5
+ --- !ruby/object:Gem::Specification
6
+ name: refinery
7
+ version: !ruby/object:Gem::Version
8
+ version: "0"
9
+ platform: ruby
10
+ authors:
11
+ - elliottcable
12
+ autorequire:
13
+ bindir: bin
14
+
15
+ date: 2008-10-12 00:00:00 -08:00
16
+ default_executable:
17
+ dependencies:
18
+ - !ruby/object:Gem::Dependency
19
+ name: echoe
20
+ type: :development
21
+ version_requirement:
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.1
27
+ version:
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec
30
+ type: :development
31
+ version_requirement:
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: "0"
37
+ version:
38
+ - !ruby/object:Gem::Dependency
39
+ name: rcov
40
+ type: :development
41
+ version_requirement:
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ - !ruby/object:Gem::Dependency
49
+ name: yard
50
+ type: :development
51
+ version_requirement:
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ - !ruby/object:Gem::Dependency
59
+ name: stringray
60
+ type: :development
61
+ version_requirement:
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ description: Mmmmagic
69
+ email:
70
+ - Refinery@elliottcable.com
71
+ executables: []
72
+
73
+ extensions:
74
+ - ext/sing/extconf.rb
75
+ extra_rdoc_files:
76
+ - ext/sing/extconf.rb
77
+ - ext/sing/sing.c
78
+ - lib/refinery/core_ext/class.rb
79
+ - lib/refinery/core_ext/object.rb
80
+ - lib/refinery.rb
81
+ - LICENSE.text
82
+ - README.markdown
83
+ files:
84
+ - ext/sing/extconf.rb
85
+ - ext/sing/sing.c
86
+ - lib/refinery/core_ext/class.rb
87
+ - lib/refinery/core_ext/object.rb
88
+ - lib/refinery.rb
89
+ - LICENSE.text
90
+ - Rakefile.rb
91
+ - README.markdown
92
+ - spec/refinery/core_ext/class_spec.rb
93
+ - spec/refinery_spec.rb
94
+ - spec/spec_helper.rb
95
+ - .manifest
96
+ - refinery.gemspec
97
+ has_rdoc: true
98
+ homepage: http://github.com/elliottcable/refinery
99
+ post_install_message:
100
+ rdoc_options:
101
+ - --line-numbers
102
+ - --inline-source
103
+ - --title
104
+ - Refinery
105
+ - --main
106
+ - README.markdown
107
+ require_paths:
108
+ - lib
109
+ - ext
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: "0"
115
+ version:
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: "1.2"
121
+ version:
122
+ requirements: []
123
+
124
+ rubyforge_project: refinery
125
+ rubygems_version: 1.3.0
126
+ specification_version: 2
127
+ summary: Mmmmagic
128
+ test_files: []
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Class do
4
+ describe '#is_singleton?' do
5
+
6
+ it 'should return false for a normal class' do
7
+ klass = Class.new
8
+ klass.should_not be_singleton
9
+ end
10
+
11
+ it 'should return true for a singleton class' do
12
+ klass = Class.new
13
+ sing = klass.class_eval { class << self; self; end }
14
+ sing.should be_singleton
15
+ end
16
+
17
+ end
18
+ end