[DRE-commits] [ruby-monkey-lib] 01/02: Imported Upstream version 0.5.4

Richard Winters devrik-guest at moszumanska.debian.org
Sat May 2 20:01:56 UTC 2015


This is an automated email from the git hooks/post-receive script.

devrik-guest pushed a commit to branch master
in repository ruby-monkey-lib.

commit ede7575f3366702dd03ce66d659d72676a725f60
Author: Richard B Winters <rik at mmogp.com>
Date:   Fri May 1 12:17:41 2015 -0400

    Imported Upstream version 0.5.4
---
 LICENSE                                      |  27 +++
 README.rdoc                                  |  47 ++++
 Rakefile                                     | 126 ++++++++++
 lib/monkey-lib.rb                            |  15 ++
 lib/monkey.rb                                |  56 +++++
 lib/monkey/autoloader.rb                     |  45 ++++
 lib/monkey/backend.rb                        | 140 +++++++++++
 lib/monkey/backend/active_support.rb         |  30 +++
 lib/monkey/backend/backports.rb              |  11 +
 lib/monkey/backend/common/extract_options.rb |  12 +
 lib/monkey/backend/common/parent.rb          |  12 +
 lib/monkey/backend/common/singleton_class.rb |  14 ++
 lib/monkey/backend/common/tap.rb             |  13 ++
 lib/monkey/backend/extlib.rb                 |  14 ++
 lib/monkey/backend/facets.rb                 |  18 ++
 lib/monkey/engine.rb                         | 139 +++++++++++
 lib/monkey/ext.rb                            | 111 +++++++++
 lib/monkey/ext/array.rb                      |  19 ++
 lib/monkey/ext/enumerable.rb                 |  20 ++
 lib/monkey/ext/file.rb                       |  12 +
 lib/monkey/ext/module.rb                     |  28 +++
 lib/monkey/ext/object.rb                     |  50 ++++
 lib/monkey/ext/pathname.rb                   |  25 ++
 lib/monkey/ext/string.rb                     | 179 +++++++++++++++
 lib/monkey/ext/symbol.rb                     |  11 +
 lib/monkey/hash_fix.rb                       |   2 +
 lib/monkey/matcher.rb                        |  11 +
 lib/monkey/version.rb                        |  35 +++
 metadata.yml                                 | 146 ++++++++++++
 spec/monkey/backend_spec.rb                  |   7 +
 spec/monkey/engine_spec.rb                   |  55 +++++
 spec/monkey/ext/array_spec.rb                |  37 +++
 spec/monkey/ext/enumerable_spec.rb           |  28 +++
 spec/monkey/ext/module_spec.rb               |  32 +++
 spec/monkey/ext/object_spec.rb               |  53 +++++
 spec/monkey/ext/pathname_spec.rb             |   0
 spec/monkey/ext/string_spec.rb               | 332 +++++++++++++++++++++++++++
 spec/monkey/ext/symbol_spec.rb               |  20 ++
 spec/monkey/ext_spec.rb                      |  50 ++++
 spec/monkey/matcher_spec.rb                  |  17 ++
 spec/monkey_spec.rb                          |  25 ++
 spec/spec_helper.rb                          |  26 +++
 42 files changed, 2050 insertions(+)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..dd8b891
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+copyright (c) 2009 Konstantin Haase.  All rights reserved.
+
+Developed by: Konstantin Haase
+              http://github.com/rkh/monkey-lib
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal with the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimers.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimers in the
+     documentation and/or other materials provided with the distribution.
+  3. Neither the name of Konstantin Haase, nor the names of other contributors
+     may be used to endorse or promote products derived from this Software without
+     specific prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+WITH THE SOFTWARE.
diff --git a/README.rdoc b/README.rdoc
new file mode 100644
index 0000000..cd1f97d
--- /dev/null
+++ b/README.rdoc
@@ -0,0 +1,47 @@
+Makes ruby extension libraries pluggable (thus not forcing such a library
+on the users of your library - like BigBand - but still giving you some
+fancy features).
+
+TODO: Describe what it actually does. Feel free to have a look at the specs/code, should
+be pretty easy to understand.
+
+Version number will soon be synchronized with BigBand.
+
+== Backends
+Those libraries are supported as backends out of the box:
+* ActiveSupport (tested with 2.3.2 to 3.0.beta)
+* Backports (tested with 1.11.1 to 1.15.0, >= 1.13.1 required for Rubinius)
+* Extlib (tested with 0.9.13 and 0.9.14)
+* Facets (tested with 2.8.0 to 2.8.2)
+
+== Ruby versions
+MonkeyLib has been tested and is known to work with the following Ruby implementations:
+
+* Ruby (MRI) 1.8.6, 1.8.7, 1.9.1, 1.9.2-preview1, also tested with trunk on regular basis
+* Ruby Enterprise Edition 2009.10, 2010.01
+* Rubinius 1.0.0-rc2 to 1.0.0-rc4, also tested with master branch on regular basis
+* JRuby 1.3.1, 1.4.0
+* MagLev 22780 to 23191 (Backports backend recommended, but all expectations pass on all backends)
+* IronRuby 0.9.3, 1.0-rc2 (only Extlib and Backports)
+
+Currently it does *not* run on MacRuby, but I'm working on it.
+
+== Running the specs
+
+Run specs with all backends:
+  rake spec
+
+Run specs with active_support:
+  rake spec:active_support
+
+Run specs with backports and using mspec instead of rspec (so it might work on incomplete ruby implementations):
+  SPEC_RUNNER=mspec rake spec:backports
+
+Sometimes there are issues with running rake from the ruby implementation (maybe rake is not fully supported, or the backend detection messes
+with your ruby). You can use one ruby implementation to run the specs on another one. For instance, I use rvm to manage my rubies:
+
+  rvm install macruby-0.5
+  rvm use macruby-0.5
+  gem install mspec backports
+  rvm use default
+  RUBY=$rvm_path/rubies/macruby-0.5/bin/ruby SPEC_RUNNER=mspec rake spec:backports
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..6a3eb39
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,126 @@
+require "rake/clean"
+
+task :default => :spec
+
+backends = Dir.glob('lib/monkey/backend/*.rb').map { |f| File.basename f, ".rb" }
+modes = [:autodetect, :explicit]
+
+CLEAN.include "**/*.rbc"
+CLOBBER.include "monkey-lib*.gem"
+
+setup_rspec = proc do
+  require "spec/rake/spectask"
+  SPEC_RUNNER = "mspec"
+  def define_spec_task(name, ruby_cmd, pattern)
+    Spec::Rake::SpecTask.new name do |t|
+      t.spec_opts += %w[-b -c --format progress --loadby mtime --reverse]
+      t.ruby_cmd = ruby_cmd
+      t.pattern = pattern
+    end
+  end
+end
+
+setup_mspec = proc do
+  require "mspec"
+  SPEC_RUNNER = "mspec"
+  def define_spec_task(name, ruby_cmd, pattern)
+    task(name) { sh "#{ruby_cmd} -S mspec-run #{pattern}" }
+  end
+end
+
+case ENV['SPEC_RUNNER']
+when "rspec" then setup_rspec.call
+when "mspec" then setup_mspec.call
+when nil
+  # yes, this code is trying to be smart, but let me have some fun, please?
+  raise @spec_load_error unless [setup_rspec, setup_mspec].any? { |b| b.call || true rescue (@spec_load_error ||= $!) && false }
+else
+  puts "sorry, currently no #{ENV['SPEC_RUNNER']} support"
+  exit 1
+end
+
+def backend_available?(backend = nil)
+  require backend unless backend.nil?
+  true
+rescue LoadError
+  false
+end
+
+def spec_task(name, backend = nil, mode = nil)
+  desc "runs specs #{"with backend #{backend} " if backend}#{"(#{mode} mode)" if mode}"
+  if backend_available? backend
+    define_spec_task(name, "BACKEND=#{backend.to_s.inspect} BACKEND_SETUP=#{mode.to_s.inspect} #{ENV['RUBY'] || RUBY}", "spec/**/*_spec.rb")
+  else
+    task(name) do
+      puts "", "could not load #{backend.inspect}, skipping specs.", ""
+    end
+  end
+end
+
+task :environment do
+  $LOAD_PATH.unshift "lib"
+  require "monkey-lib"
+end
+
+desc "run all specs"
+task :spec => "spec:all"
+namespace :spec do
+
+  desc "runs specs without explicitly setting a backend"
+  spec_task :autodetect
+
+  backends.each do |backend|
+    task :all => backend
+
+    desc "runs specs with backend #{backend}"
+    task backend => "#{backend}:all"
+
+    namespace backend do
+      modes.each do |mode|
+        task :all => mode
+        spec_task mode, backend, mode
+      end
+    end
+
+  end
+end
+
+namespace :backend do
+
+  desc "lists all available backends"
+  task(:list) { puts backends }
+
+  desc "lists expectations a backend has to meet"
+  task :expectations => :environment do
+    Monkey::Ext.expectations.each do |core_class, methods|
+      print "#{core_class}:".ljust(10)
+      puts methods.map { |n| "##{n}" }.join(", ")
+    end
+  end
+
+  desc "checks whether specs for expectations are present"
+  task :spec_check =>:environment do
+    Monkey::Ext.expectations.each do |core_class, methods|
+      path = "spec/monkey/ext/#{core_class.name.to_const_path}_spec.rb"
+      list = path.file_exists? ? %x[spec -d -fs #{path} -e "Monkey::Ext::#{core_class.name} backend expectations"] : ""
+      methods.each { |m| puts "missing specs for #{core_class.name}##{m}" unless list =~ /- imports #{m} from backend/ }
+    end
+  end
+
+end
+
+############
+# aliases
+
+namespace(:b) do
+  task :e => "backend:expectations"
+  task :l => "backend:list"
+  task :s => "backend:spec_check"
+end
+
+namespace(:s) do
+  task :as => "spec:active_support:explicit"
+  task :bp => "spec:backports:explicit"
+  task :ex => "spec:extlib:explicit"
+  task :fc => "spec:facets:explicit"
+end
diff --git a/lib/monkey-lib.rb b/lib/monkey-lib.rb
new file mode 100644
index 0000000..b6f629a
--- /dev/null
+++ b/lib/monkey-lib.rb
@@ -0,0 +1,15 @@
+require "monkey"
+
+unless defined? Monkey
+  warn "installing both the monkey and the monkey-lib gem results in conflicts, add a Gemfile, use gemsets or remove monkey gem"
+  $LOADED_FEATURES.delete_if { |l| l =~ /monkey\.rb$/ }
+  if defined? require_relative
+    require_relative "monkey"
+  else
+    $LOAD_PATH.unshift File.expand_path('..', __FILE__)
+    require 'monkey'
+  end
+  fail "Please remove monkey gem (not monkey-lib gem) from your $LOAD_PATH" unless defined? Monkey
+end
+
+MonkeyLib = Monkey
diff --git a/lib/monkey.rb b/lib/monkey.rb
new file mode 100644
index 0000000..581a6f3
--- /dev/null
+++ b/lib/monkey.rb
@@ -0,0 +1,56 @@
+module Monkey
+  def self.backend=(backend)
+    Backend.setup! backend
+    backend
+  end
+
+  def self.backend
+    Backend.backend
+  end
+
+  def self.invisible(*from)
+    yield
+  rescue Exception => error
+    unless show_invisibles?
+      from << caller.first[/^[^:]*/] if from.empty?
+      from << __FILE__
+      delete_from_backtrace(error) { |l| from.any? { |f| l.include? f } }
+    end
+    raise error
+  end
+
+  def self.show_invisibles?
+    !!@show_invisibles
+  end
+
+  def self.show_invisibles!(show = true)
+    return @show_invisibles = show unless block_given?
+    # actually, that is not thread-safe. but that's no issue, as
+    # it is quite unlikely and does not cause any harm.
+    show_invisibles_was, @show_invisibles = @show_invisibles, show
+    result = yield
+    @show_invisibles = show_invisibles_was
+    result
+  end
+
+  def self.hide_invisibles!(&block)
+    show_invisibles!(false, &block)
+  end
+
+  def self.delete_from_backtrace(error, &block)
+    if error.respond_to? :awesome_backtrace
+      # HACK: we rely on the internal data structure, btw
+      locations = error.instance_variable_get :@locations
+      return unless locations
+      locations.reject! { |l| yield l.position }
+      error.instance_variable_set :@backtrace, nil
+    else
+      error.backtrace.reject!(&block)
+    end
+  end
+
+  Dir[File.dirname(__FILE__) + "/monkey/*.rb"].sort.each do |path|
+    filename = File.basename(path, '.rb')
+    require "monkey/#{filename}"
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/autoloader.rb b/lib/monkey/autoloader.rb
new file mode 100644
index 0000000..727416b
--- /dev/null
+++ b/lib/monkey/autoloader.rb
@@ -0,0 +1,45 @@
+require "monkey-lib"
+
+Module.class_eval do
+  alias const_missing_without_detection const_missing
+
+  def const_missing(const_name)
+    if respond_to? :parent and parent.autoloader? and not is_a? Monkey::Autoloader
+      extend Monkey::Autoloader
+      const_missing const_name
+    else
+      Monkey.invisible(__FILE__) { const_missing_without_detection const_name }
+    end
+  end
+
+  def autoloader?
+    is_a? Monkey::Autoloader or (respond_to? :parent and parent != self and parent.autoloader?)
+  end
+end
+
+module Monkey
+  module Autoloader
+    def const_missing(const_name)
+      const_name = const_name.to_s
+      file = File.join(self.name.to_const_path, const_name.to_const_path)
+      begin
+        require file
+        if const_defined? const_name
+          const = const_get const_name
+          const.extend Monkey::Autoloader
+          const
+        else
+          warn "expected #{file} to define #{name}::#{const_name}"
+          raise LoadError
+        end
+      rescue LoadError => error
+        begin
+          return parent.const_get(const_name) if respond_to? :parent and parent != self
+        rescue NameError
+        end
+        warn "tried to load #{file}: #{error.message}"
+        super
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/backend.rb b/lib/monkey/backend.rb
new file mode 100644
index 0000000..b3d0829
--- /dev/null
+++ b/lib/monkey/backend.rb
@@ -0,0 +1,140 @@
+module Monkey
+  module Backend
+
+    @available_backends = []
+
+    class << self
+      attr_reader :available_backends, :backend
+    end
+
+    module AbstractBackend
+      attr_accessor :backend_name, :backend_path
+
+      def available?
+        return true if Object.const_defined? backend_name
+        $LOADED_FEATURES.any? do |f|
+          f =~ /^(.*lib\/)?#{backend_path}|#{backend_path}(-[^\/]+)?\/lib/
+        end
+      end
+
+      def setup_complete
+        require backend_path
+        setup
+      end
+
+      def load_libs(*data)
+        load_with_prefix backend_path, data
+      end
+
+      alias load_lib load_libs
+
+      def load_with_prefix(prefix, libs = nil)
+        case libs
+        when String, Symbol then require File.join(prefix.to_s, libs.to_s)
+        when Array then libs.each { |lib| load_with_prefix prefix, lib }
+        when Hash then libs.each { |k, v| load_with_prefix File.join(prefix.to_s, k.to_s), v }
+        else raise ArgumentError, "cannot handle #{libs.inspect}"
+        end
+      end
+
+      def missing(*libs)
+        load_with_prefix "monkey/backend/common", libs
+      end
+
+      def expects_module(name)
+        name.split("::").inject(Object) do |parent, name|
+          if name.empty?
+            parent
+          else
+            parent.class_eval "module #{name}; self; end"
+          end
+        end
+      end
+
+      def version(default = "0")
+        return version(nil) || default unless default.nil?
+        return @version if @version
+        return unless defined? Gem
+        Gem.send :attr_accessor, :loaded_specs
+        return unless Gem.loaded_specs.respond_to? :[]
+        @version = Gem.loaded_specs[gem_name].version.to_s if Gem.loaded_specs.include? gem_name
+      end
+
+      def version!
+        version(nil) or raise RuntimeError, "unable to determine backend version"
+      end
+
+      def version?
+        !!version(false)
+      end
+
+      def gem_name
+        @gem_name ||= name[/[^:]*$/].downcase
+      end
+
+    end
+
+    def self.new(backend_name, backend_path = nil, &block)
+      mod = eval "module #{backend_name}; self; end"
+      mod.extend AbstractBackend
+      backend_path ||= backend_name.to_s.downcase
+      mod.backend_name, mod.backend_path = backend_name.to_s, backend_path.to_s
+      available_backends << mod
+      if block
+        eigenclass = class << mod; self; end
+        eigenclass.class_eval(&block)
+      end
+      mod
+    end
+
+    def self.preferred_backend
+      available_backends.detect { |b| b.available? } || @backend
+    end
+
+    def self.setup?
+      !!@setup
+    end
+
+    def self.setup!(backend)
+      if backend
+        @setup = true
+        @backend = detect_backend(backend)
+        @backend.setup
+        @backend
+      else
+        available_backends.each do |backend|
+          begin
+            return setup!(backend)
+          rescue LoadError => error
+            @load_error ||= error
+            @backend = nil
+          end
+        end  
+        raise @load_error
+      end
+    end
+
+    class << self
+      alias backend= setup!
+    end
+
+    def self.setup
+      setup! preferred_backend unless setup?
+    end
+
+    def self.detect_backend(backend_or_name)
+      return backend_or_name if backend_or_name.respond_to? :setup
+      detected = available_backends.detect do |backend|
+        [backend.backend_name.to_s, backend.backend_path.to_s, backend.name.to_s].include? backend_or_name.to_s
+      end
+      raise ArgumentError, "cannot detect backend #{backend_or_name.inspect}" unless detected
+      detected
+    end
+
+    require "monkey/backend/backports"
+    require "monkey/backend/active_support"
+    require "monkey/backend/facets"
+    require "monkey/backend/extlib"
+
+  end
+end
diff --git a/lib/monkey/backend/active_support.rb b/lib/monkey/backend/active_support.rb
new file mode 100644
index 0000000..9f4f1ee
--- /dev/null
+++ b/lib/monkey/backend/active_support.rb
@@ -0,0 +1,30 @@
+Monkey::Backend.new :ActiveSupport, :active_support do
+  def setup
+    load_lib :version
+    expects_module "::ActiveSupport::CoreExtensions::String::Inflections" if version < "3"
+    load_libs :core_ext => %w[array/extract_options string/inflections module/introspection]
+    if version < "3"
+      begin
+        load_libs "core_ext/object/singleton_class"
+      rescue LoadError
+        load_libs "core_ext/object/metaclass"
+        ::Object.send(:alias_method, :singleton_class, :metaclass)
+      end
+      load_libs "core_ext/object/misc"
+      ::Array.send  :include, ::ActiveSupport::CoreExtensions::Array::ExtractOptions
+      ::Module.send :include, ::ActiveSupport::CoreExtensions::Module
+      ::String.send :include, ::ActiveSupport::CoreExtensions::String::Inflections
+    else
+      load_libs "core_ext/kernel/singleton_class"
+    end
+    ::String.send(:alias_method, :to_const_string, :camelcase)
+    ::String.send(:alias_method, :to_const_path, :underscore)
+  end
+
+  def version(default = "0")
+    load_lib :version
+    @version ||= ActiveSupport::VERSION::STRING or super
+  rescue NameError
+    super
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/backend/backports.rb b/lib/monkey/backend/backports.rb
new file mode 100644
index 0000000..a0063a4
--- /dev/null
+++ b/lib/monkey/backend/backports.rb
@@ -0,0 +1,11 @@
+Monkey::Backend.new :Backports do
+  def setup
+    load_libs "tools", "1.8.7/kernel", :rails => [:array, :string]
+    missing :parent, :singleton_class
+    ::String.class_eval do
+      alias camelcase camelize
+      alias to_const_string camelize
+      alias to_const_path underscore
+    end
+  end
+end
diff --git a/lib/monkey/backend/common/extract_options.rb b/lib/monkey/backend/common/extract_options.rb
new file mode 100644
index 0000000..fcce80b
--- /dev/null
+++ b/lib/monkey/backend/common/extract_options.rb
@@ -0,0 +1,12 @@
+module Monkey
+  module Backend
+    module Common
+      module ExtractOptions
+        ::Array.send :include, self
+        def extract_options!
+          last.is_a?(::Hash) ? pop : {}
+        end
+      end
+    end
+  end
+end
diff --git a/lib/monkey/backend/common/parent.rb b/lib/monkey/backend/common/parent.rb
new file mode 100644
index 0000000..b7dca91
--- /dev/null
+++ b/lib/monkey/backend/common/parent.rb
@@ -0,0 +1,12 @@
+module Monkey
+  module Backend
+    module Common
+      module Parent
+        ::Module.send :include, self
+        def parent
+          name && name =~ /^(.+)::[^:]+$/ ? $1.constantize : Object
+        end
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/backend/common/singleton_class.rb b/lib/monkey/backend/common/singleton_class.rb
new file mode 100644
index 0000000..a117b8f
--- /dev/null
+++ b/lib/monkey/backend/common/singleton_class.rb
@@ -0,0 +1,14 @@
+module Monkey
+  module Backend
+    module Common
+      module SingletonClass
+        ::Object.send :include, self
+        def singleton_class
+          class << self
+            self
+          end
+        end
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/backend/common/tap.rb b/lib/monkey/backend/common/tap.rb
new file mode 100644
index 0000000..aba12a3
--- /dev/null
+++ b/lib/monkey/backend/common/tap.rb
@@ -0,0 +1,13 @@
+module Monkey
+  module Backend
+    module Common
+      module Tap
+        ::Object.send :include, self
+        def tap
+          yield self
+          self
+        end
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/backend/extlib.rb b/lib/monkey/backend/extlib.rb
new file mode 100644
index 0000000..ef06fea
--- /dev/null
+++ b/lib/monkey/backend/extlib.rb
@@ -0,0 +1,14 @@
+Monkey::Backend.new :Extlib do
+  def setup
+    load_libs :object, :string, :inflection
+    missing :parent, :extract_options, :tap
+    ::Object.class_eval { alias singleton_class meta_class }
+    ::String.class_eval do
+      alias camelcase to_const_string
+      alias underscore to_const_path
+      def constantize
+        Extlib::Inflection.constantize(self)
+      end
+    end
+  end
+end
diff --git a/lib/monkey/backend/facets.rb b/lib/monkey/backend/facets.rb
new file mode 100644
index 0000000..1ca6b4d
--- /dev/null
+++ b/lib/monkey/backend/facets.rb
@@ -0,0 +1,18 @@
+Monkey::Backend.new :Facets do
+  def setup
+    load_libs :kernel => [:meta_class, :constant], :string => [:camelcase, :snakecase]
+    # Actually, facets has Kernel#tap, but it behaves different if the block takes no argument.
+    missing :tap, :extract_options, :parent
+    ::String.class_eval do
+      def constantize
+        constant to_const_string
+      end
+      alias to_const_string upper_camelcase
+      alias to_const_path snakecase
+      alias underscore snakecase
+    end
+    ::Object.class_eval do
+      alias singleton_class meta_class unless respond_to? :singleton_class
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/engine.rb b/lib/monkey/engine.rb
new file mode 100644
index 0000000..f2ba0bb
--- /dev/null
+++ b/lib/monkey/engine.rb
@@ -0,0 +1,139 @@
+module Monkey
+
+  # Makes sure we always have RUBY_ENGINE, RUBY_ENGINE_VERSION and RUBY_DESCRIPTION
+  # TODO: Check IronRuby version detection.
+  module Engine
+
+    def jruby?;    RUBY_ENGINE == "jruby";    end
+    def mri?;      RUBY_ENGINE == "ruby";     end
+    def rbx?;      RUBY_ENGINE == "rbx";      end
+    def ironruby?; RUBY_ENGINE == "ironruby"; end
+    def macruby?;  RUBY_ENGINE == "macruby";  end
+    def maglev?;   RUBY_ENGINE == "maglev";   end
+
+    alias rubinius? rbx?
+
+    def ree?
+      !!(RUBY_DESCRIPTION =~ /Ruby Enterprise Edition/) || RUBY_ENGINE == "ree"
+    end
+
+    module_function :jruby?
+    module_function :mri?
+    module_function :rbx?
+    module_function :rubinius?
+    module_function :ironruby?
+    module_function :macruby?
+    module_function :maglev?
+    module_function :ree?
+
+    def ruby_core?
+      maglev? or rubinius?
+    end
+
+    module_function :ruby_core?
+
+    include Rubinius if defined? Rubinius
+
+    unless defined? RUBY_ENGINE
+      if    defined? JRUBY_VERSION then ::RUBY_ENGINE = "jruby"
+      elsif defined? Rubinius      then ::RUBY_ENGINE = "rbx"
+      elsif defined? NSObject      then ::RUBY_ENINGE = "macruby"
+      elsif defined? Maglev        then ::RUBY_ENINGE = "maglev"
+      else                              ::RUBY_ENGINE = "ruby"
+      end
+    end
+
+    unless RUBY_ENGINE.frozen?
+      RUBY_ENGINE.replace "rbx" if RUBY_ENGINE == "rubinius"
+      RUBY_ENGINE.downcase!
+      RUBY_ENGINE.freeze
+    end
+
+    unless defined? RUBY_ENGINE_VERSION
+      begin
+        # ruby, jruby, macruby, some rubinius versions
+        ::RUBY_ENGINE_VERSION = const_get("#{RUBY_ENGINE.upcase}_VERSION")
+      rescue NameError
+        # maglev, some rubinius versions
+        ::RUBY_ENGINE_VERSION = const_get("VERSION")
+      end
+    end
+
+    unless defined? RUBY_DESCRIPTION
+      ::RUBY_DESCRIPTION = "#{RUBY_ENGINE} #{RUBY_ENGINE_VERSION} "
+      unless RUBY_ENGINE == "ruby"
+        ::RUBY_DESCRIPTION << "(ruby #{RUBY_VERSION}"
+        ::RUBY_DESCRIPTION << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
+        ::RUBY_DESCRIPTION << ") "
+      end
+      if defined? RUBY_RELEASE_DATE
+        ::RUBY_DESCRIPTION << "("
+        ::RUBY_DESCRIPTION << BUILDREV[0..8] << " " if defined? BUILDREV
+        ::RUBY_DESCRIPTION << RUBY_RELEASE_DATE << ") "
+      end
+      ::RUBY_DESCRIPTION << "[#{RUBY_PLATFORM}]"
+    end
+
+    if ree?
+      ::REAL_RUBY_ENGINE_VERSION = ::REE_VERSION = RUBY_DESCRIPTION[/[^ ]+$/]
+      ::REAL_RUBY_ENGINE = "ree"
+    else
+      ::REAL_RUBY_ENGINE, ::REAL_RUBY_ENGINE_VERSION = ::RUBY_ENGINE, ::RUBY_ENGINE_VERSION
+    end
+
+    def ruby_engine(engine = RUBY_ENGINE, pretty = true)
+      return engine unless pretty
+      case engine
+      when "ruby"   then ree? ? "Ruby Enterprise Edition" : "Ruby"
+      when "ree"    then "Ruby Enterprise Edition"
+      when "rbx"    then "Rubinius"
+      when "maglev" then "MagLev"
+      else engine.capitalize.gsub("ruby", "Ruby")
+      end
+    end
+
+    module_function :ruby_engine
+    
+    def self.set_engine(engine, engine_version = nil)
+      Object.send :remove_const, "RUBY_ENGINE"
+      Object.const_set "RUBY_ENGINE", engine
+      if engine_version
+        Object.send :remove_const, "RUBY_ENGINE_VERSION"
+        Object.const_set "RUBY_ENGINE_VERSION", engine_version
+      end
+    end
+
+    def with_ruby_engine(engine, engine_version)
+      engine_was, engine_version_was = ::RUBY_ENGINE, ::RUBY_ENGINE_VERSION
+      unless defined? ::OLD_RUBY_ENGINE
+        Object.const_set("OLD_RUBY_ENGINE", ::RUBY_ENGINE)
+        Object.const_set("OLD_RUBY_ENGINE_VERSION", ::RUBY_ENGINE_VERSION)
+      end
+      Monkey::Engine.set_engine engine, engine_version
+      if block_given?
+        result = yield
+        Monkey::Engine.set_engine engine_was, engine_version_was
+        result
+      else
+        [engine_was, engine_version_was]
+      end
+    end
+
+    module_function :with_ruby_engine
+
+    def use_real_ruby_engine(&block)
+      with_ruby_engine(::REAL_RUBY_ENGINE, ::REAL_RUBY_ENGINE_VERSION, &block)
+    end
+
+    module_function :use_real_ruby_engine
+
+    def use_original_ruby_engine(&block)
+      if defined? ::OLD_RUBY_ENGINE then with_ruby_engine(::OLD_RUBY_ENGINE, ::OLD_RUBY_ENGINE_VERSION, &block)
+      else with_ruby_engine(::RUBY_ENGINE, ::RUBY_ENGINE_VERSION, &block)
+      end
+    end
+
+    module_function :use_original_ruby_engine
+
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/ext.rb b/lib/monkey/ext.rb
new file mode 100644
index 0000000..cd66990
--- /dev/null
+++ b/lib/monkey/ext.rb
@@ -0,0 +1,111 @@
+require "pathname"
+require "monkey/engine"
+
+module Monkey
+  module Ext
+
+    module ExtDSL
+
+      module ClassDsl
+        include ExtDSL
+        def core_class(klass = nil)
+          klass ? @core_class = klass : @core_class
+        end
+      end
+
+      def core_class(klass = nil)
+        if klass
+          @core_class = klass
+          klass.send :include, self
+          self::ExtClassMethods.extend ClassDsl
+          self::ExtClassMethods.core_class @core_class
+          @core_class.class_eval <<-EOS
+            def method_missing(meth, *args, &blk)
+              return super if Monkey::Backend.setup?
+              Monkey::Backend.setup
+              __send__(meth, *args, &blk)
+            end
+          EOS
+          propagate_include
+        end
+        @core_class
+      end
+
+      if Monkey::Engine.jruby? and JRUBY_VERSION < '1.6.0'
+        def each_module(&block)
+          list = []
+          ObjectSpace.each_object(Class) { |c| list << c }
+          list.each(&block)
+        end
+      else
+        def each_module(&block)
+          ObjectSpace.each_object(Module, &block)
+        end
+      end
+
+      def propagate_include
+        return if core_class.is_a? Class
+        each_module do |mod|
+          next unless mod < core_class and not mod < self
+          mod.send(:include, core_class)
+        end
+      end
+
+      def included(klass)
+        klass.extend self::ExtClassMethods
+        super
+      end
+
+      def rename_core_method(old_name, new_name)
+        core_class.send :undef_method, alias_core_method(old_name, new_name)
+      end
+
+      def alias_core_method(old_name, new_name)
+        new_name = new_name % old_name if new_name.is_a? String
+        core_class.send :alias_method, new_name, old_name
+        old_name
+      end
+
+      def feature(name, mode = :instance, &block)
+        case mode
+        when :instance then block.call
+        when :class then class_methods(&block)
+        when :shared
+          feature(name, :instance, &block)
+          feature(name, :class, &block)
+        else raise ArgumentError, "unkown mode #{mode.inspect}"
+        end
+      end
+
+      def class_methods(&block)
+        self::ExtClassMethods.class_eval(&block)
+      end
+
+      def expects(*list)
+        list.each do |name|
+          Monkey::Ext.expectations[core_class] << name.to_s
+        end
+      end
+
+    end
+
+    def self.expectations
+      @expectations ||= Hash.new { |h,k| h[k] = [] }
+    end
+
+    Dir[::File.dirname(__FILE__) + "/ext/*.rb"].sort.each do |path|
+      filename   = ::File.basename(path, '.rb')
+      class_name = filename.capitalize
+      extension  = eval <<-EOS
+        module ::Monkey::Ext::#{class_name} # <- for MacRuby!?
+          module ExtClassMethods; end          # <- for 1.9
+          self
+        end
+      EOS
+      extension.extend ExtDSL
+      extension.core_class ::Object.const_get(class_name)
+      require "monkey/ext/#{filename}"
+    end
+
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/ext/array.rb b/lib/monkey/ext/array.rb
new file mode 100644
index 0000000..e893c1a
--- /dev/null
+++ b/lib/monkey/ext/array.rb
@@ -0,0 +1,19 @@
+require 'set'
+
+module Monkey
+  module Ext
+    module Array
+      # Defined by backend.
+      expects :extract_options!
+
+      def select!(&block)
+        return :to_enum if block.nil? and respond_to? :to_enum
+        replace select(&block)
+      end
+
+      def +@
+        Set.new self
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/ext/enumerable.rb b/lib/monkey/ext/enumerable.rb
new file mode 100644
index 0000000..e84c4be
--- /dev/null
+++ b/lib/monkey/ext/enumerable.rb
@@ -0,0 +1,20 @@
+module Monkey
+  module Ext
+    module Enumerable
+      def construct(obj)
+        enum_for :construct, obj unless block_given? or !respond_to? :enum_for
+        inject(obj) { |a,v| a.tap { yield(a, v) } }
+      end
+
+      def construct_hash(default = {})
+        enum_for :construct_hash unless block_given? or !respond_to? :enum_for
+        construct(default.to_hash.dup) do |h,v|
+          result = yield(v)
+          result = [result, nil] unless result.is_a? Enumerable
+          result = [result] unless result.respond_to? :to_ary
+          h.merge! Hash[*result]
+        end
+      end
+    end
+  end
+end
diff --git a/lib/monkey/ext/file.rb b/lib/monkey/ext/file.rb
new file mode 100644
index 0000000..dd860e2
--- /dev/null
+++ b/lib/monkey/ext/file.rb
@@ -0,0 +1,12 @@
+module Monkey
+  module Ext
+    module File
+      module ExtClassMethods
+        def write(path, content = '', mode = 'w')
+          File.open(path, mode) { |f| f.write content }
+          content
+        end
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/ext/module.rb b/lib/monkey/ext/module.rb
new file mode 100644
index 0000000..cc921bf
--- /dev/null
+++ b/lib/monkey/ext/module.rb
@@ -0,0 +1,28 @@
+module Monkey
+  module Ext
+    module Module
+      # Defined by backend.
+      expects :parent
+
+      def nested_method_missing(mod, name, *args, &block)
+        Monkey.invisible __FILE__ do
+          if respond_to? :parent and parent != self
+            parent.send(:nested_method_missing, mod, name, *args, &block)
+          else
+            mod.send(:method_missing_without_nesting, name, *args) 
+          end
+        end
+      end
+
+      def method_missing(name, *args, &block)
+        if respond_to? :parent and parent.respond_to? :nested_method_missing
+          parent.nested_method_missing(self, name, *args, &block)
+        else
+          method_missing_without_nesting(name, *args, &block)
+        end
+      end
+
+    end
+  end
+end
+
diff --git a/lib/monkey/ext/object.rb b/lib/monkey/ext/object.rb
new file mode 100644
index 0000000..49f15f2
--- /dev/null
+++ b/lib/monkey/ext/object.rb
@@ -0,0 +1,50 @@
+module Monkey
+  module Ext
+    module Object
+
+      # Defined by backend.
+      expects :singleton_class, :tap
+
+      # Behaves like instance_eval or yield depending on whether a block takes an argument or not.
+      #
+      #   class Foo
+      #     define_method(:foo) { 42 }
+      #   end
+      #
+      #   Foo.new.instance_yield { foo }        # => 42
+      #   Foo.new.instance_yield { |c| c.foo }  # => 42
+      #
+      # Also, you can pass a proc directly:
+      #
+      #   block = proc { }
+      #   instance_yield(block)
+      def instance_yield(block = nil, &alternate_block)
+        raise ArgumentError, "too many blocks given" if block && alternate_block
+        block ||= alternate_block
+        raise LocalJumpError, "no block given (yield)" unless block
+        block.arity > 0 ? yield(self) : instance_eval(&block)
+      end
+
+      def singleton_class_eval(&block)
+        singleton_class.class_eval(&block)
+      end
+
+      def define_singleton_method(name, &block)
+        singleton_class_eval { define_method(name, &block) }
+      end
+
+      def metaclass
+        warn "DEPRECATION WARNING: #metaclass will be removed, use #singleton_class (#{caller})"
+        singleton_class
+      end
+
+      def metaclass_eval(&block)
+        warn "DEPRECATION WARNING: #metaclass_eval will be removed, use #singleton_class_eval (#{caller})"
+        singleton_class_eval(&block)
+      end
+
+      alias_core_method :method_missing, :method_missing_without_nesting
+
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/ext/pathname.rb b/lib/monkey/ext/pathname.rb
new file mode 100644
index 0000000..d2662fd
--- /dev/null
+++ b/lib/monkey/ext/pathname.rb
@@ -0,0 +1,25 @@
+require "pathname"
+
+module Monkey
+  module Ext
+    module Pathname
+      ##
+      # @return [Pathname, NilClass] Path with correct casing.
+      def cased_path
+        return unless exist?
+        return Dir.chdir(self) { Pathname(Dir.pwd) } if ::File.directory? path
+        files = Dir.chdir(dirname) { Dir.entries('.').select { |f| f.downcase == basename.to_s.downcase } }
+        dirname.cased_path.join(files.size == 1 ? files.first : basename)
+      end
+      
+      def chdir(&block)
+        Dir.chdir(self.to_s, &block)
+      end
+      
+      def open(mode = "r", &block)
+        File.open(self, mode, &block)
+      end
+      
+    end
+  end
+end
diff --git a/lib/monkey/ext/string.rb b/lib/monkey/ext/string.rb
new file mode 100644
index 0000000..93526b4
--- /dev/null
+++ b/lib/monkey/ext/string.rb
@@ -0,0 +1,179 @@
+require "pathname"
+
+module Monkey
+  module Ext
+    module String
+      # Defined by backend.
+      expects :constantize, :to_const_string, :to_const_path, :underscore, :camelcase
+
+      feature :version do
+        def to_version
+          dup.to_version!
+        end
+
+        def to_version!
+          extend Monkey::Version
+          self
+        end
+      end
+
+      feature :pathname do
+        def atime
+          Pathname(self).atime
+        end
+
+        def absolute_path?
+          Pathname(self).absolute?
+        end
+
+        def basename
+          Pathname(self).basename.to_s
+        end
+
+        def blockdev?
+          Pathname(self).blockdev?
+        end
+
+        def chardev?
+          Pathname(self).chardev?
+        end
+
+        def cleanpath
+          Pathname(self).cleanpath.to_s
+        end
+
+        def ctime
+          Pathname(self).ctime
+        end
+
+        def directory_children
+          Pathname(self).children
+        end
+
+        def directory?
+          Pathname(self).directory?
+        end
+
+        def dirname
+          Pathname(self).dirname.to_s
+        end
+
+        def cased_path
+          Pathname(self).cased_path.to_s
+        end
+
+        def chdir(&block)
+          Pathname(self).chdir(&block)
+        end
+
+        def expand_path
+          Pathname(self).expand_path.to_s
+        end
+
+        def extname
+          Pathname(self).extname.to_s
+        end
+
+        def file?
+          Pathname(self).file?
+        end
+
+        def file_exist?
+          Pathname(self).exist?
+        end
+
+        alias file_exists? file_exist?
+
+        def file_grpowned?
+          Pathname(self).grpowned?
+        end
+
+        def file_owned?
+          Pathname(self).owned?
+        end
+
+        def file_size?
+          Pathname(self).size?
+        end
+
+        def file_sticky?
+          Pathname(self).sticky?
+        end
+
+        def file_executable?
+          Pathname(self).executable?
+        end
+
+        def file_executable_real?
+          Pathname(self).executable_real?
+        end
+
+        def file_join(other)
+          Pathname(self).join(other.to_s).to_s
+        end
+
+        alias / file_join
+
+        def file_open(mode = 'r', &block)
+          Pathname(self).open(mode = 'r', &block)
+        end
+
+        def file_readable?
+          Pathname(self).readable?
+        end
+
+        def file_readable_real?
+          Pathname(self).readable_real?
+        end
+
+        def file_relative?
+          Pathname(self).relative?
+        end
+
+        def file_writable?
+          Pathname(self).writable?
+        end
+
+        def file_writable_real?
+          Pathname(self).writable_real?
+        end
+
+        def file_zero?
+          Pathname(self).zero?
+        end
+
+        def ftype
+          Pathname(self).ftype.to_s
+        end
+
+        def mountpoint?
+          Pathname(self).mountpoint?
+        end
+
+        def mtime
+          Pathname(self).mtime
+        end
+
+        def pipe?
+          Pathname(self).pipe?
+        end
+
+        def realpath
+          Pathname(self).realpath.to_s
+        end
+
+        def root?
+          Pathname(self).root?
+        end
+
+        def socket?
+          Pathname(self).socket?
+        end
+
+        def symlink?
+          Pathname(self).symlink?
+        end
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/ext/symbol.rb b/lib/monkey/ext/symbol.rb
new file mode 100644
index 0000000..9851e0f
--- /dev/null
+++ b/lib/monkey/ext/symbol.rb
@@ -0,0 +1,11 @@
+module Monkey
+  module Ext
+    module Symbol
+      def ~@
+        Monkey::Matcher.new do |obj|
+          obj.respond_to?(self)
+        end
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/monkey/hash_fix.rb b/lib/monkey/hash_fix.rb
new file mode 100644
index 0000000..4dbb5fa
--- /dev/null
+++ b/lib/monkey/hash_fix.rb
@@ -0,0 +1,2 @@
+require 'monkey/engine'
+Hash.class_eval { def hash; to_a.hash end } if Monkey::Engine.mri? and RUBY_VERSION < '1.8.7'
diff --git a/lib/monkey/matcher.rb b/lib/monkey/matcher.rb
new file mode 100644
index 0000000..44cd851
--- /dev/null
+++ b/lib/monkey/matcher.rb
@@ -0,0 +1,11 @@
+module Monkey
+  class Matcher
+    def initialize(&block)
+      @block = block
+    end
+
+    def ===(other)
+      @block.call(other)
+    end
+  end
+end
diff --git a/lib/monkey/version.rb b/lib/monkey/version.rb
new file mode 100644
index 0000000..cbe9095
--- /dev/null
+++ b/lib/monkey/version.rb
@@ -0,0 +1,35 @@
+module Monkey
+  module Version
+    def self.new(value = "")
+      super.to_version!
+    end
+
+    def to_version
+      self.dup
+    end
+
+    def to_version!
+      self
+    end
+
+    def major; fields[0]; end
+    def minor; fields[1]; end
+    def tiny;  fields[2]; end
+
+    def <=>(other)
+      return super unless other.respond_to? :to_version
+      mine, others = fields.dup, other.to_version.fields
+      loop do
+        a, b = mine.unshift, others.unshift
+        return  0 if a.nil? and b.nil?
+        return  1 if b.nil? or (a.is_a? Integer and b.is_a? String)
+        return -1 if a.nil? or (b.is_a? Integer and a.is_a? String)
+        return comp unless (comp = (a <=> b)) == 0
+      end
+    end
+
+    def fields
+      split(".").map { |f| f =~ /^\d+$/ ? f.to_i : f }
+    end
+  end
+end
\ No newline at end of file
diff --git a/metadata.yml b/metadata.yml
new file mode 100644
index 0000000..9db7f4a
--- /dev/null
+++ b/metadata.yml
@@ -0,0 +1,146 @@
+--- !ruby/object:Gem::Specification 
+name: monkey-lib
+version: !ruby/object:Gem::Version 
+  hash: 3
+  prerelease: false
+  segments: 
+  - 0
+  - 5
+  - 4
+  version: 0.5.4
+platform: ruby
+authors: 
+- Konstantin Haase
+autorequire: 
+bindir: bin
+cert_chain: []
+
+date: 2010-09-20 00:00:00 +02:00
+default_executable: 
+dependencies: 
+- !ruby/object:Gem::Dependency 
+  name: backports
+  prerelease: false
+  requirement: &id001 !ruby/object:Gem::Requirement 
+    none: false
+    requirements: 
+    - - ">="
+      - !ruby/object:Gem::Version 
+        hash: 3
+        segments: 
+        - 0
+        version: "0"
+  type: :runtime
+  version_requirements: *id001
+description: Making ruby extension frameworks pluggable.
+email: konstantin.mailinglists at googlemail.com
+executables: []
+
+extensions: []
+
+extra_rdoc_files: 
+- README.rdoc
+- LICENSE
+- lib/monkey/autoloader.rb
+- lib/monkey/backend/active_support.rb
+- lib/monkey/backend/backports.rb
+- lib/monkey/backend/common/extract_options.rb
+- lib/monkey/backend/common/parent.rb
+- lib/monkey/backend/common/singleton_class.rb
+- lib/monkey/backend/common/tap.rb
+- lib/monkey/backend/extlib.rb
+- lib/monkey/backend/facets.rb
+- lib/monkey/backend.rb
+- lib/monkey/engine.rb
+- lib/monkey/ext/array.rb
+- lib/monkey/ext/enumerable.rb
+- lib/monkey/ext/file.rb
+- lib/monkey/ext/module.rb
+- lib/monkey/ext/object.rb
+- lib/monkey/ext/pathname.rb
+- lib/monkey/ext/string.rb
+- lib/monkey/ext/symbol.rb
+- lib/monkey/ext.rb
+- lib/monkey/hash_fix.rb
+- lib/monkey/matcher.rb
+- lib/monkey/version.rb
+- lib/monkey-lib.rb
+- lib/monkey.rb
+files: 
+- LICENSE
+- Rakefile
+- README.rdoc
+- lib/monkey/autoloader.rb
+- lib/monkey/backend/active_support.rb
+- lib/monkey/backend/backports.rb
+- lib/monkey/backend/common/extract_options.rb
+- lib/monkey/backend/common/parent.rb
+- lib/monkey/backend/common/singleton_class.rb
+- lib/monkey/backend/common/tap.rb
+- lib/monkey/backend/extlib.rb
+- lib/monkey/backend/facets.rb
+- lib/monkey/backend.rb
+- lib/monkey/engine.rb
+- lib/monkey/ext/array.rb
+- lib/monkey/ext/enumerable.rb
+- lib/monkey/ext/file.rb
+- lib/monkey/ext/module.rb
+- lib/monkey/ext/object.rb
+- lib/monkey/ext/pathname.rb
+- lib/monkey/ext/string.rb
+- lib/monkey/ext/symbol.rb
+- lib/monkey/ext.rb
+- lib/monkey/hash_fix.rb
+- lib/monkey/matcher.rb
+- lib/monkey/version.rb
+- lib/monkey-lib.rb
+- lib/monkey.rb
+- spec/monkey/backend_spec.rb
+- spec/monkey/engine_spec.rb
+- spec/monkey/ext/array_spec.rb
+- spec/monkey/ext/enumerable_spec.rb
+- spec/monkey/ext/module_spec.rb
+- spec/monkey/ext/object_spec.rb
+- spec/monkey/ext/pathname_spec.rb
+- spec/monkey/ext/string_spec.rb
+- spec/monkey/ext/symbol_spec.rb
+- spec/monkey/ext_spec.rb
+- spec/monkey/matcher_spec.rb
+- spec/monkey_spec.rb
+- spec/spec_helper.rb
+has_rdoc: true
+homepage: http://github.com/rkh/monkey-lib
+licenses: []
+
+post_install_message: 
+rdoc_options: []
+
+require_paths: 
+- lib
+required_ruby_version: !ruby/object:Gem::Requirement 
+  none: false
+  requirements: 
+  - - ">="
+    - !ruby/object:Gem::Version 
+      hash: 3
+      segments: 
+      - 0
+      version: "0"
+required_rubygems_version: !ruby/object:Gem::Requirement 
+  none: false
+  requirements: 
+  - - ">="
+    - !ruby/object:Gem::Version 
+      hash: 3
+      segments: 
+      - 0
+      version: "0"
+requirements: []
+
+rubyforge_project: 
+rubygems_version: 1.3.7
+signing_key: 
+specification_version: 3
+summary: Making ruby extension frameworks pluggable.
+test_files: []
+
diff --git a/spec/monkey/backend_spec.rb b/spec/monkey/backend_spec.rb
new file mode 100644
index 0000000..13ccfce
--- /dev/null
+++ b/spec/monkey/backend_spec.rb
@@ -0,0 +1,7 @@
+require __FILE__.sub(%r{monkey/.*$}, "spec_helper")
+
+describe Monkey::Backend do
+  it "should preffer backports unless any backend already has been loaded" do
+    Monkey::Backend.available_backends.first.should == Monkey::Backend::Backports
+  end
+end
diff --git a/spec/monkey/engine_spec.rb b/spec/monkey/engine_spec.rb
new file mode 100644
index 0000000..27ca78a
--- /dev/null
+++ b/spec/monkey/engine_spec.rb
@@ -0,0 +1,55 @@
+require __FILE__.sub(%r{monkey/.*$}, "spec_helper")
+
+describe Monkey::Engine do
+
+  it "defines RUBY_VERSION" do
+    defined?(RUBY_VERSION).should == "constant"
+  end
+
+  it "defines RUBY_ENGINE_VERSION" do
+    defined?(RUBY_ENGINE_VERSION).should == "constant"
+  end
+
+  it "defines RUBY_DESCRIPTION" do
+    defined?(RUBY_DESCRIPTION).should == "constant"
+  end
+
+  it "defines REAL_RUBY_VERSION" do
+    defined?(RUBY_VERSION).should == "constant"
+  end
+
+  it "defines REAL_RUBY_ENGINE_VERSION" do
+    defined?(RUBY_ENGINE_VERSION).should == "constant"
+  end
+
+  describe "with_ruby_engine" do
+
+    it "sets RUBY_ENGINE and RUBY_ENGINE_VERSION" do
+      Monkey::Engine.with_ruby_engine("jruby", "1.4.0") do
+        RUBY_ENGINE.should == "jruby"
+        RUBY_ENGINE_VERSION.should == "1.4.0"
+        Monkey::Engine.should be_jruby
+      end
+      Monkey::Engine.with_ruby_engine("ruby", "1.8.7") do
+        RUBY_ENGINE.should == "ruby"
+        RUBY_ENGINE_VERSION.should == "1.8.7"
+        Monkey::Engine.should be_mri
+      end
+    end
+
+    it "restores old RUBY_ENGINE if block given" do
+      old = RUBY_ENGINE
+      Monkey::Engine.with_ruby_engine("foobar", "1.0") { }
+      RUBY_ENGINE.should_not == "foobar"
+      RUBY_ENGINE.should == old
+    end
+
+    it "restores old RUBY_ENGINE_VERSION if block given" do
+      old = RUBY_ENGINE_VERSION
+      Monkey::Engine.with_ruby_engine("foobar", "1.0") { }
+      RUBY_ENGINE_VERSION.should == old
+    end
+
+  end
+
+end
\ No newline at end of file
diff --git a/spec/monkey/ext/array_spec.rb b/spec/monkey/ext/array_spec.rb
new file mode 100644
index 0000000..8cd81ee
--- /dev/null
+++ b/spec/monkey/ext/array_spec.rb
@@ -0,0 +1,37 @@
+require __FILE__.sub(%r{monkey/.*$}, "spec_helper")
+
+describe Monkey::Ext::Array do
+  describe "backend expectations" do
+    # expects :extract_options!
+    it "imports extract_options! from backend" do
+      [:foo, {:x => 10}].extract_options!.should == {:x => 10}
+      [:foo].extract_options!.should == {}
+      [{:x => 10}, :foo].extract_options!.should == {}
+      ary1 = [:foo, {:x => 10}]
+      ary1.extract_options!
+      ary1.should == [:foo]
+      ary2 = [{:x => 10}, :foo]
+      ary2.extract_options!
+      ary2.should == [{:x => 10}, :foo]
+    end
+  end
+
+  describe "select!" do
+    it "results in the same arrays as Array#select" do
+      ([1, 2, 3, 4, 5, 6].select! { |e| e > 3 }).should == ([1, 2, 3, 4, 5, 6].select { |e| e > 3 })
+      ([1, 2, 3, 4, 5, 6].select! { |e| e < 0 }).should == ([1, 2, 3, 4, 5, 6].select { |e| e < 0 })
+    end
+
+    it "modifies the current array, rather than returning a new one" do
+      x = [1, 2, 3, 4, 5, 6]
+      x.select! { |e| e > 3 }
+      x.should == [4, 5, 6]
+    end
+  end
+
+  describe '+@' do
+    it 'returns a set' do
+      (+[1,2]).should be_a(Set)
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/monkey/ext/enumerable_spec.rb b/spec/monkey/ext/enumerable_spec.rb
new file mode 100644
index 0000000..addbc76
--- /dev/null
+++ b/spec/monkey/ext/enumerable_spec.rb
@@ -0,0 +1,28 @@
+require __FILE__.sub(%r{monkey/.*$}, "spec_helper")
+
+describe Monkey::Ext::Enumerable do
+  describe :construct do
+    it "always returns the initial object" do
+      obj = Object.new
+      (1..100).construct(obj) { "not obj" }.should == obj
+    end
+
+    it "allows modifying that object" do
+      ("a".."c").construct("result: ") { |a,v| a << v }.should == "result: abc"
+    end
+  end
+
+  describe :construct_hash do
+    it "constructs a hash from given hashes" do
+      ("a".."b").construct_hash { |v| { v => v } }.should == { "a" => "a", "b" => "b" }
+    end
+
+    it "constructs a hash from given arrays" do
+      ("a".."b").construct_hash { |v| [v, v] }.should == { "a" => "a", "b" => "b" }
+    end
+
+    it "takes an initial hash" do
+      ["a"].construct_hash("b" => "b") { |v| [v, v] }.should == { "a" => "a", "b" => "b" }
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/monkey/ext/module_spec.rb b/spec/monkey/ext/module_spec.rb
new file mode 100644
index 0000000..489670d
--- /dev/null
+++ b/spec/monkey/ext/module_spec.rb
@@ -0,0 +1,32 @@
+require __FILE__.sub(%r{monkey/.*$}, "spec_helper")
+
+describe Monkey::Ext::Module do
+  describe "backend expectations" do
+    # expects :parent
+    it "imports parent from backend" do
+      Monkey::Ext::Module.parent.should == Monkey::Ext
+      Monkey::Ext.parent.should == Monkey
+      Monkey.parent.should == Object
+      Object.parent.should == Object
+      Object.send :remove_const, :ExtFoo if Object.const_defined? :ExtFoo
+      ExtFoo = Monkey::Ext::Module
+      ExtFoo.parent.should == Monkey::Ext
+    end
+  end
+
+  describe "nested_method_missing" do
+
+    before do
+      [:Foo, :Bar, :Blah].inject(Object) do |parent, name|
+        parent.send :remove_const, name if parent.const_defined? name
+        parent.const_set name, Module.new
+      end
+    end
+
+    it "should call nested_method_missing on parent" do
+      Foo.should_receive(:nested_method_missing).once.with(Foo::Bar, :foo)
+      Foo::Bar.foo
+    end
+
+  end
+end
diff --git a/spec/monkey/ext/object_spec.rb b/spec/monkey/ext/object_spec.rb
new file mode 100644
index 0000000..0e21691
--- /dev/null
+++ b/spec/monkey/ext/object_spec.rb
@@ -0,0 +1,53 @@
+require __FILE__.sub(%r{monkey/.*$}, "spec_helper")
+
+describe Monkey::Ext::Object do
+
+  before do
+    @obj = Object.new
+  end
+
+  describe "backend expectations" do
+
+    # expects :tap
+    it "imports tap from backend" do
+      @obj.tap { |o| o.should == @obj }
+      42.tap { 23 }.should == 42
+    end
+
+    # expects :singleton_class
+    it "imports singleton_class from backend" do
+      @obj.singleton_class.should == (class << @obj; self; end)
+    end
+
+  end
+
+  describe :instance_yield do
+
+    before do
+      @obj.stub! :foo
+    end
+
+    it "calls a block if block takes at least one argument" do
+      foo = nil
+      @obj.should_not_receive :foo
+      @obj.send :instance_yield do |x|
+        foo
+      end
+    end 
+
+    it "passes object as first argument to blog" do
+      @obj.send :instance_yield do |x|
+        x.should == @obj
+      end
+    end
+
+    it "passes the block to instance_eval if block doesn't take arguments" do
+      @obj.should_receive :foo
+      @obj.send :instance_yield do
+        foo
+      end
+    end
+
+  end
+
+end
\ No newline at end of file
diff --git a/spec/monkey/ext/pathname_spec.rb b/spec/monkey/ext/pathname_spec.rb
new file mode 100644
index 0000000..e69de29
diff --git a/spec/monkey/ext/string_spec.rb b/spec/monkey/ext/string_spec.rb
new file mode 100644
index 0000000..623cf7f
--- /dev/null
+++ b/spec/monkey/ext/string_spec.rb
@@ -0,0 +1,332 @@
+require __FILE__.sub(%r{monkey/.*$}, "spec_helper")
+
+describe Monkey::Ext::String do
+
+  describe "backend expectations" do
+
+    # expects :constantize :underscore, :camelcase
+    it "imports constantize from backend" do
+      "Object".constantize.should == Object
+      "Monkey::Ext".constantize.should == Monkey::Ext
+    end
+
+    # expects :to_const_string
+    it "imports to_const_string from backend" do
+      "object".to_const_string.should == "Object"
+      "monkey/ext".to_const_string.should == "Monkey::Ext"
+    end
+
+    # expects :to_const_path
+    it "imports to_const_path from backend" do
+      "Object".to_const_path.should == "object"
+      "Monkey::Ext".to_const_path.should == "monkey/ext"
+    end
+
+    # expects :underscore
+    it "imports underscore from backend" do
+      "FooBar".underscore.should == "foo_bar"
+    end
+
+    # expects :camelcase
+    it "imports camelcase from backend" do
+      ["FooBar", "fooBar"].should include("foo_bar".camelcase)
+    end
+
+  end
+
+  describe "like Pathname" do
+
+    before do
+      @strings = ["/usr/bin/ruby", ".", "..", ENV["HOME"]]
+    end
+
+    it "imports Pathname's cleanpath to String" do
+      @strings.each do |s|
+        s.cleanpath.should == Pathname(s).cleanpath.to_s
+      end
+    end
+
+    it "imports Pathname's realpath to String" do
+      @strings.each do |s|
+        begin
+          s.realpath.should == Pathname(s).realpath.to_s
+        rescue Errno::ENOENT
+        end
+      end
+    end
+
+    it "imports Pathname's mountpoint? to String" do
+      @strings.each do |s|
+        s.mountpoint?.should == Pathname(s).mountpoint?
+      end
+    end
+
+    it "imports Pathname's root? to String" do
+      @strings.each do |s|
+        s.root?.should == Pathname(s).root?
+      end
+    end
+
+    it "imports Pathname's absolute_path? to String" do
+      @strings.each do |s|
+        s.absolute_path?.should == Pathname(s).absolute?
+      end
+    end
+
+    it "imports Pathname's file_relative? to String" do
+      @strings.each do |s|
+        s.file_relative?.should == Pathname(s).relative?
+      end
+    end
+
+    it "imports Pathname's file_join to String" do
+      @strings.each do |s|
+        s.file_join("foo").should == Pathname(s).join("foo").to_s
+        s.file_join(:foo).should == Pathname(s).join("foo").to_s
+      end
+    end
+
+    it "imports Pathname's atime to String" do
+      @strings.each do |s|
+        s.atime.should == Pathname(s).atime
+      end
+    end
+
+    it "imports Pathname's ctime to String" do
+      @strings.each do |s|
+        s.ctime.should == Pathname(s).ctime
+      end
+    end
+
+    it "imports Pathname's mtime to String" do
+      @strings.each do |s|
+        s.mtime.should == Pathname(s).mtime
+      end
+    end    
+
+    it "imports Pathname's ftype to String" do
+      @strings.each do |s|
+        s.ftype.should == Pathname(s).ftype.to_s
+      end
+    end
+
+    it "imports Pathname's basename to String" do
+      @strings.each do |s|
+        s.basename.should == Pathname(s).basename.to_s
+      end
+    end
+
+    it "imports Pathname's dirname to String" do
+      @strings.each do |s|
+        s.dirname.should == Pathname(s).dirname.to_s
+      end
+    end
+
+    it "imports Pathname's extname to String" do
+      @strings.each do |s|
+        s.extname.should == Pathname(s).extname.to_s
+      end
+    end
+
+    it "imports Pathname's expand_path to String" do
+      @strings.each do |s|
+        s.expand_path.should == Pathname(s).expand_path.to_s
+      end
+    end
+
+    it "imports Pathname's blockdev? to String" do
+      @strings.each do |s|
+        s.blockdev?.should == Pathname(s).blockdev?
+      end
+    end
+
+    it "imports Pathname's chardev? to String" do
+      @strings.each do |s|
+        s.chardev?.should == Pathname(s).chardev?
+      end
+    end
+
+    it "imports Pathname's file_executable? to String" do
+      @strings.each do |s|
+        s.file_executable?.should == Pathname(s).executable?
+      end
+    end
+
+    it "imports Pathname's file_executable_real? to String" do
+      @strings.each do |s|
+        s.file_executable_real?.should == Pathname(s).executable_real?
+      end
+    end
+
+    it "imports Pathname's atime to String" do
+      @strings.each do |s|
+        s.atime.should == Pathname(s).atime
+      end
+    end
+
+    it "imports Pathname's ctime to String" do
+      @strings.each do |s|
+        s.ctime.should == Pathname(s).ctime
+      end
+    end
+
+    it "imports Pathname's mtime to String" do
+      @strings.each do |s|
+        s.mtime.should == Pathname(s).mtime
+      end
+    end    
+
+    it "imports Pathname's ftype to String" do
+      @strings.each do |s|
+        s.ftype.should == Pathname(s).ftype.to_s
+      end
+    end
+
+    it "imports Pathname's basename to String" do
+      @strings.each do |s|
+        s.basename.should == Pathname(s).basename.to_s
+      end
+    end
+
+    it "imports Pathname's dirname to String" do
+      @strings.each do |s|
+        s.dirname.should == Pathname(s).dirname.to_s
+      end
+    end
+
+    it "imports Pathname's extname to String" do
+      @strings.each do |s|
+        s.extname.should == Pathname(s).extname.to_s
+      end
+    end
+
+    it "imports Pathname's expand_path to String" do
+      @strings.each do |s|
+        s.expand_path.should == Pathname(s).expand_path.to_s
+      end
+    end
+
+    it "imports Pathname's blockdev? to String" do
+      @strings.each do |s|
+        s.blockdev?.should == Pathname(s).blockdev?
+      end
+    end
+
+    it "imports Pathname's chardev? to String" do
+      @strings.each do |s|
+        s.chardev?.should == Pathname(s).chardev?
+      end
+    end
+
+    it "imports Pathname's file_executable? to String" do
+      @strings.each do |s|
+        s.file_executable?.should == Pathname(s).executable?
+      end
+    end
+
+    it "imports Pathname's file_executable_real? to String" do
+      @strings.each do |s|
+        s.file_executable_real?.should == Pathname(s).executable_real?
+      end
+    end
+
+    it "imports Pathname's directory? to String" do
+      @strings.each do |s|
+        s.directory?.should == Pathname(s).directory?
+      end
+    end
+
+    it "imports Pathname's file? to String" do
+      @strings.each do |s|
+        s.file?.should == Pathname(s).file?
+      end
+    end
+
+    it "imports Pathname's pipe? to String" do
+      @strings.each do |s|
+        s.pipe?.should == Pathname(s).pipe?
+      end
+    end
+
+    it "imports Pathname's socket? to String" do
+      @strings.each do |s|
+        s.socket?.should == Pathname(s).socket?
+      end
+    end
+
+    it "imports Pathname's file_owned? to String" do
+      @strings.each do |s|
+        s.file_owned?.should == Pathname(s).owned?
+      end
+    end
+
+    it "imports Pathname's file_readable? to String" do
+      @strings.each do |s|
+        s.file_readable?.should == Pathname(s).readable?
+      end
+    end
+
+    it "imports Pathname's file_readable_real? to String" do
+      @strings.each do |s|
+        s.file_readable_real?.should == Pathname(s).readable_real?
+      end
+    end
+
+    it "imports Pathname's symlink? to String" do
+      @strings.each do |s|
+        s.symlink?.should == Pathname(s).symlink?
+      end
+    end
+
+    it "imports Pathname's file_writable? to String" do
+      @strings.each do |s|
+        s.file_writable?.should == Pathname(s).writable?
+      end
+    end
+
+    it "imports Pathname's file_writable_real? to String" do
+      @strings.each do |s|
+        s.file_writable_real?.should == Pathname(s).writable_real?
+      end
+    end
+
+    it "imports Pathname's file_zero? to String" do
+      @strings.each do |s|
+        s.file_zero?.should == Pathname(s).zero?
+      end
+    end
+
+    it "imports Pathname's file_exist? to String" do
+      @strings.each do |s|
+        s.file_exist?.should == Pathname(s).exist?
+        s.file_exists?.should == Pathname(s).exist? 
+      end
+    end
+
+    it "imports Pathname's file_grpowned? to String" do
+      @strings.each do |s|
+        s.file_grpowned?.should == Pathname(s).grpowned?
+      end
+    end
+
+    it "imports Pathname's file_size? to String" do
+      @strings.each do |s|
+        s.file_size?.should == Pathname(s).size?
+      end
+    end
+
+    it "imports Pathname's file_sticky? to String" do
+      @strings.each do |s|
+        s.file_sticky?.should == Pathname(s).sticky?
+      end
+    end
+
+    it "imports Pathname's directory_children to String" do
+      @strings.each do |s|
+        s.directory_children.should == Pathname(s).children if s.directory?
+      end
+    end
+
+  end
+
+end
\ No newline at end of file
diff --git a/spec/monkey/ext/symbol_spec.rb b/spec/monkey/ext/symbol_spec.rb
new file mode 100644
index 0000000..1cf2755
--- /dev/null
+++ b/spec/monkey/ext/symbol_spec.rb
@@ -0,0 +1,20 @@
+require __FILE__.sub(%r{monkey/.*$}, "spec_helper")
+
+describe Monkey::Ext::Symbol do
+  describe '~@' do
+    it 'should match objects responding to a method' do
+      matcher = ~:foo
+      o = Object.new
+      (matcher === o).should be_false
+      o.stub! :foo
+      (matcher === o).should be_true
+    end
+
+    it 'should work for case statements' do
+      case 'foo'
+      when ~:to_s then nil
+      else fail 'did not match'
+      end
+    end
+  end
+end
diff --git a/spec/monkey/ext_spec.rb b/spec/monkey/ext_spec.rb
new file mode 100644
index 0000000..f15e99d
--- /dev/null
+++ b/spec/monkey/ext_spec.rb
@@ -0,0 +1,50 @@
+require __FILE__.sub(%r{monkey/.*$}, "spec_helper")
+
+describe Monkey::Ext do
+  describe Monkey::Ext::ExtDSL do
+
+    before do
+      @core_class = Class.new
+      @extension = Module.new
+      @extension::ExtClassMethods = Module.new
+      @extension.extend Monkey::Ext::ExtDSL
+      @extension.core_class @core_class
+    end
+
+    it "extends the core class" do
+      @core_class.ancestors.should include(@extension)
+    end
+
+    it "adds methods to the core class instances" do
+      instance = @core_class.new
+      @extension.class_eval do
+        def foo
+          42
+        end
+      end
+      instance.foo.should == 42
+    end
+
+    it "adds methods to the core class" do
+      @extension.class_methods do
+        def foo
+          42
+        end
+      end
+      @core_class.foo.should == 42
+    end
+
+    it "is able to rename core instance methods" do
+      instance = @core_class.new
+      @core_class.class_eval do
+        def foo
+          42
+        end
+      end
+      @extension.rename_core_method :foo, :bar
+      instance.should_not respond_to(:foo)
+      instance.bar.should == 42
+    end
+
+  end
+end
diff --git a/spec/monkey/matcher_spec.rb b/spec/monkey/matcher_spec.rb
new file mode 100644
index 0000000..3319620
--- /dev/null
+++ b/spec/monkey/matcher_spec.rb
@@ -0,0 +1,17 @@
+require __FILE__.sub(%r{monkey/.*$}, "spec_helper")
+
+describe Monkey::Matcher do
+  it 'should consider block for #===' do
+    matcher = Monkey::Matcher.new { |x| x > 6 }
+    (matcher === 5).should be_false
+    (matcher === 8).should be_true
+  end
+
+  it 'should work with switch' do
+    matcher = Monkey::Matcher.new { |x| /foo/ === x }
+    case 'foobar'
+    when matcher then nil
+    else fail 'did not match'
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/monkey_spec.rb b/spec/monkey_spec.rb
new file mode 100644
index 0000000..5c416ef
--- /dev/null
+++ b/spec/monkey_spec.rb
@@ -0,0 +1,25 @@
+require __FILE__.sub(%r{monkey_spec\.rb$}, "spec_helper")
+
+describe Monkey do
+  describe :invisible do
+    it "removes lines from a backtrace" do
+      Monkey.hide_invisibles! do
+        begin
+          Monkey.invisible(__FILE__) { raise }
+        rescue
+          $!.backtrace.each do |line|
+            line.should_not include(__FILE__)
+          end
+        end
+      end
+    end
+  end
+
+  if BACKEND
+    describe "backend" do
+      it "uses backend #{ENV['BACKEND']}" do
+        Monkey.backend.should == Monkey::Backend.detect_backend(BACKEND)
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..7f3c013
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,26 @@
+$LOAD_PATH.unshift File.expand_path(__FILE__.sub("spec/spec_helper.rb", "lib"))
+require "monkey-lib"
+
+# I hate that code, but rbx for some reason ignores RUBYOPT.
+begin
+  require "rubygems"
+rescue LoadError
+end
+
+BACKEND, BACKEND_SETUP = ENV['BACKEND'], ENV['BACKEND_SETUP']
+if BACKEND and not BACKEND.empty?
+  case BACKEND_SETUP
+  when "autodetect"
+    require BACKEND
+    Monkey::Backend.setup
+  when "explicit"
+    Monkey.backend = BACKEND
+  else
+    puts "Please set BACKEND_SETUP."
+    exit 1
+  end
+  version = "version " << Monkey.backend.version << ", " if Monkey.backend.version?
+  puts "Using #{BACKEND} (#{version}#{BACKEND_SETUP} setup mode)"
+end
+
+Monkey.show_invisibles!

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-monkey-lib.git



More information about the Pkg-ruby-extras-commits mailing list