├── .gitignore ├── CHANGELOG.md ├── Gemfile ├── Gemfile.lock ├── Manifest.txt ├── README.md ├── Rakefile ├── lib └── base.rb ├── spec └── base_spec.rb └── test-against-multiple-rubies.sh /.gitignore: -------------------------------------------------------------------------------- 1 | /pkg 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # base Changelog 2 | 3 | ### 0.0.1 / 2011-09-01 4 | 5 | * Project Created 6 | 7 | ### 0.0.2 / 2011-09-02 8 | 9 | * Performance improvements from @dkubb 10 | * Attempt to call methods on classes whose constructors take arguments 11 | 12 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | gem "hoe" 3 | gem "rspec" 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | diff-lcs (1.1.3) 5 | hoe (3.0.8) 6 | rake (~> 0.8) 7 | rake (0.9.2.2) 8 | rspec (2.11.0) 9 | rspec-core (~> 2.11.0) 10 | rspec-expectations (~> 2.11.0) 11 | rspec-mocks (~> 2.11.0) 12 | rspec-core (2.11.1) 13 | rspec-expectations (2.11.2) 14 | diff-lcs (~> 1.1.3) 15 | rspec-mocks (2.11.2) 16 | 17 | PLATFORMS 18 | ruby 19 | 20 | DEPENDENCIES 21 | hoe 22 | rspec 23 | -------------------------------------------------------------------------------- /Manifest.txt: -------------------------------------------------------------------------------- 1 | CHANGELOG.md 2 | Manifest.txt 3 | README.md 4 | Rakefile 5 | lib/base.rb 6 | spec/base_spec.rb 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Base 2 | 3 | * http://github.com/garybernhardt/base 4 | 5 | ## DESCRIPTION: 6 | 7 | People love Base classes! They have tons of methods waiting to be used. Just check out `ActiveRecord::Base`'s method list: 8 | 9 | ```irb 10 | >> ActiveRecord::Base.methods.length 11 | => 572 12 | ``` 13 | 14 | But why stop there? Why not have even more methods? In fact, let's put *every method* on one Base class! 15 | 16 | So I did. It's called Base. Just subclass it and feel free to directly reference any class method, instance method, or constant defined on any module or class in the system. Like this: 17 | 18 | ```ruby 19 | class Cantaloupe < Base 20 | def embiggen 21 | encode64(deflate(SEPARATOR)) 22 | end 23 | end 24 | 25 | >> Cantaloupe.new.embiggen 26 | => "eJzTBwAAMAAw\n" 27 | ``` 28 | 29 | See that `embiggen` method calling `encode64` and `deflate` methods? Those come from the `Base64` and `Zlib` modules. And the `SEPARATOR` constant is defined in `File`. Base don't care where it's defined! Base calls what it wants! 30 | 31 | By the way, remember those 572 ActiveRecord methods? That's amateur stuff. Check out Base loaded inside a Rails app: 32 | 33 | ```irb 34 | >> Base.new.methods.count 35 | => 5794 36 | ``` 37 | 38 | It's so badass that it takes *five seconds* just to answer that question! 39 | 40 | Base is just craaazzy! It's the most fearless class in all of Ruby. Base doesn't afraid of anything! 41 | 42 | ## LICENSE: 43 | 44 | Distributed under the union of the terms specified by all current OSI-approved licenses. In the event of a conflict, a die is to be rolled. 45 | 46 | ## PRAISE FOR BASE 47 | 48 | > @garybernhardt @kantrn ... Can't tell if joke or just Ruby. 49 | 50 | \- @[shazow](https://twitter.com/#!/shazow/status/109464406739521536) 51 | 52 | > @garybernhardt y u troll soooo good? ;-) 53 | 54 | \- @[amerine](https://twitter.com/#!/amerine/status/109453913572392960) 55 | 56 | > @garybernhardt Imagine all the things you could have done doing not that 57 | 58 | \- @[mrb_bk](https://twitter.com/#!/mrb_bk/status/109452972966154240) 59 | 60 | > @garybernhardt I hate you. 61 | 62 | \- @[jmazzi](https://twitter.com/#!/jmazzi/status/109451655040352256) 63 | 64 | ## SHOULD I USE THIS IN MY SYSTEM? 65 | 66 | Yes. I am being completely serious. You should. 67 | 68 | Definitely. 69 | 70 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'hoe' 3 | 4 | Hoe.plugin :git, :doofus, :seattlerb 5 | 6 | Hoe.spec 'base' do 7 | developer 'Gary Bernhardt', 'gary.bernhardt@gmail.com' 8 | 9 | ### Use markdown for changelog and readme 10 | self.history_file = 'CHANGELOG.md' 11 | self.readme_file = 'README.md' 12 | 13 | ### Test with rspec 14 | self.extra_dev_deps << [ 'rspec', '>= 2.1.0' ] 15 | self.testlib = :rspec 16 | 17 | ### build zip files too 18 | self.need_zip = true 19 | end 20 | 21 | # add pointer so gem test works. bleh. 22 | task :test => [:spec] 23 | 24 | -------------------------------------------------------------------------------- /lib/base.rb: -------------------------------------------------------------------------------- 1 | class Base 2 | VERSION = "0.0.2" 3 | 4 | def self.const_missing(name) 5 | all_modules.each do |mod| 6 | return mod.const_get(name) if mod.const_defined?(name) 7 | end 8 | super 9 | end 10 | 11 | def self.all_modules 12 | modules = ObjectSpace.each_object(Module).select do |mod| 13 | should_extract_from?(mod) 14 | end 15 | modules << Kernel 16 | modules 17 | end 18 | 19 | def self.should_extract_from?(mod) 20 | return false if module_is_a_base?(mod) 21 | return mod.is_a?(Module) && mod != Kernel 22 | end 23 | 24 | def self.method_missing(name, *args, &block) 25 | call_method(self, name, args, block) { super } 26 | end 27 | 28 | def method_missing(name, *args, &block) 29 | self.class.call_method(self, name, args, block) { super } 30 | end 31 | 32 | def self.call_method(object, name, args, block) 33 | all_modules.each do |mod| 34 | if mod.respond_to?(name) 35 | return mod.send(name, *args, &block) 36 | elsif module_has_instance_method?(mod, name) 37 | return call_instance_method(mod, name, args, block) 38 | end 39 | end 40 | 41 | # call "super" in the context of the method_missing caller 42 | yield 43 | end 44 | 45 | def self.module_has_instance_method?(mod, method_name) 46 | (mod.instance_methods.include?(method_name) || 47 | mod.instance_methods.include?(method_name.to_s)) 48 | end 49 | 50 | def self.call_instance_method(mod, name, args, block) 51 | if mod.is_a? Class 52 | klass = Class.new(mod) 53 | else 54 | klass = Class.new { include mod } 55 | end 56 | 57 | object = self.instantiate_regardless_of_argument_count(klass) 58 | return object.send(name, *args, &block) 59 | end 60 | 61 | def self.instantiate_regardless_of_argument_count(klass) 62 | (0..100).each do |arg_count| 63 | begin 64 | return klass.new(*[nil] * arg_count) 65 | rescue ArgumentError 66 | end 67 | end 68 | end 69 | 70 | def self.methods 71 | (giant_method_list_including_object(self) + super).uniq 72 | end 73 | 74 | def methods 75 | (self.class.giant_method_list_including_object(self) + super).uniq 76 | end 77 | 78 | # INHERIT ALL THE METHODS! 79 | def self.giant_method_list_including_object(object) 80 | methods = [] 81 | all_modules.each do |mod| 82 | unless module_is_a_base?(mod) 83 | methods.concat(mod.methods).concat(mod.instance_methods) 84 | end 85 | end 86 | methods 87 | end 88 | 89 | def self.module_is_a_base?(mod) 90 | mod.is_a?(Base) || mod < Base || mod == Base 91 | end 92 | end 93 | 94 | -------------------------------------------------------------------------------- /spec/base_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('lib/base') 2 | 3 | module NormalModule 4 | Something = 5 5 | 6 | def self.a_class_method; 6; end 7 | def a_module_method; 7; end 8 | end 9 | 10 | class NormalClass 11 | def an_instance_method; 8; end 12 | end 13 | 14 | class ClassWithTwoConstructorArgs 15 | def initialize(x, y) 16 | end 17 | 18 | def some_method 19 | "constructor args worked!" 20 | end 21 | end 22 | 23 | class InheritsFromBase < Base 24 | end 25 | 26 | describe Base do 27 | it "has other modules' constants" do 28 | InheritsFromBase::Something.should == NormalModule::Something 29 | end 30 | 31 | it "still throws NameError if the constant doesn't exist" do 32 | expect do 33 | InheritsFromBase::SomethingElse 34 | end.to raise_error NameError 35 | end 36 | 37 | it "has other modules' class methods" do 38 | InheritsFromBase.a_class_method.should == 6 39 | end 40 | 41 | it "has other modules' instance methods" do 42 | InheritsFromBase.a_module_method.should == 7 43 | end 44 | 45 | it "has other classes' instance methods" do 46 | InheritsFromBase.an_instance_method.should == 8 47 | end 48 | 49 | it "still throws NoMethodError if the method doesn't exist" do 50 | expect do 51 | InheritsFromBase.not_a_method 52 | end.to raise_error NoMethodError 53 | end 54 | 55 | it "has other modules' methods as instance methods" do 56 | InheritsFromBase.new.a_class_method.should == 6 57 | end 58 | 59 | it "includes methods from the standard library" do 60 | InheritsFromBase.inflate(InheritsFromBase.deflate("x")).should == "x" 61 | end 62 | 63 | it "checks Kernel last" do 64 | InheritsFromBase.all_modules.last.should == Kernel 65 | end 66 | 67 | its "instance NoMethodErrors reference the instance" do 68 | expect do 69 | InheritsFromBase.new.not_a_method 70 | end.to raise_error(NoMethodError, /undefined method `not_a_method' for # 1500 75 | end 76 | 77 | it "lists a lot of instance methods" do 78 | InheritsFromBase.new.methods.count.should > 1500 79 | end 80 | 81 | it "doesn't list duplicate methods" do 82 | methods = InheritsFromBase.methods 83 | methods.uniq.should == methods 84 | end 85 | 86 | it "instantiates objects with the correct number of arguments" do 87 | InheritsFromBase.new.some_method.should == "constructor args worked!" 88 | end 89 | end 90 | 91 | -------------------------------------------------------------------------------- /test-against-multiple-rubies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | rvm ree@base,1.9.2@base exec rspec spec 6 | 7 | --------------------------------------------------------------------------------