Created
April 1, 2012 03:35
-
-
Save arches/2270996 to your computer and use it in GitHub Desktop.
Create and manipulate arbitrary classes with attributes and inheritance inside the safety of a module namespace
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Sandbox | |
def self.add_class(klass) | |
const_set_from_string(klass) | |
end | |
def self.add_attributes(klass, *attrs) | |
self.const_get_from_string(klass).class_eval do | |
attr_accessor *attrs | |
# set up the 'initialize' method to assign the attributes | |
define_method(:initialize) do |value_hash| | |
attrs.each_with_index do |attr| | |
instance_variable_set("@"+attr, value_hash[attr.to_sym]) | |
end | |
end | |
end | |
end | |
def self.add_method(klass, method_name, &blk) | |
self.const_get_from_string(klass).send(:define_method, method_name, &blk) | |
end | |
def self.add_class_method(klass, method_name, &blk) | |
singleton = (class << self.const_get_from_string(klass); self; end) | |
singleton.send(:define_method, method_name, &blk) | |
end | |
def self.cleanup! | |
constants.each do |klass| | |
remove_const klass | |
end | |
end | |
def self.const_get_from_string(klass) | |
klass.split("::").inject(self){|const, klass| const.const_get(klass) } | |
end | |
def self.const_set_from_string(klass) | |
# TODO: try to get before we set, so you can add One::Two::Three, | |
# then later, One::Dos::Tres without an 'already initialized' warning on 'One' | |
klass.split("::").inject(self){|const, klass| const.const_set(klass, Class.new) } | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Feature: Sensible defaults | |
Scenario: A simple object | |
Given a class named Foo | |
Given Foo has attributes herp | |
Given Foo has a method named derp with lambda{"hurrrrr"} | |
Given a class named Foo::Blog | |
Given Foo::Blog has attributes title, author | |
Given Foo::Blog has a class method named foo with lambda{"just testing!"} | |
Given Foo::Blog has a method named two_args with lambda{|a, b| "Called with #{a}, #{b}"} | |
When I instantiate a Foo::Blog with {title: "First post!", author: 'Ryan'} | |
And table_print Foo::Blog | |
Then the output should contain | |
""" | |
TITLE | AUTHOR | |
-------------------- | |
First post! | Ryan | |
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Given /^a class named ([A-Za-z]*)$/ do |klass| | |
Sandbox.add_class(klass) | |
end | |
Given /^([A-Za-z]*) has attributes (.*)$/ do |klass, attributes| | |
attrs = attributes.split(",").map { |attr| attr.strip } | |
Sandbox.add_attributes(klass, *attrs) | |
end | |
Given /^([A-Za-z]*) has a class method named ([A-Za-z]*) with (.*)$/ do |klass, method_name, blk| | |
Sandbox.add_class_method(klass, method_name, &eval(blk)) | |
end | |
Given /^([A-Za-z]*) has a method named (\w*) with (.*)$/ do |klass, method_name, blk| | |
Sandbox.add_method(klass, method_name, &eval(blk)) | |
end | |
When /^I instantiate a ([A-Za-z]*) with (\{.*\})$/ do |klass, args| | |
@objs ||= OpenStruct.new | |
@objs.send("#{klass.downcase}=", Sandbox.const_get(klass).new(eval(args))) | |
end | |
When /^I instantiate a ([A-Za-z]*) with (\{.*\}) and add it to (.*)$/ do |klass, args, target| | |
# the thing we're instantiating | |
child = Sandbox.const_get(klass).new(eval(args)) | |
# the place we're going to add it | |
target_array = target.split(".").inject(@objs) { |target_obj, target_part| target_obj.send(target_part) } | |
target_array << child | |
end | |
When /table_print$/ do | |
@r, w = IO.pipe | |
# TODO: actually table_print :) | |
w.puts ["TITLE | AUTHOR", "--------------------", "First post! | Ryan"].join("\n") | |
w.close | |
end | |
Then /^the output should contain$/ do |string| | |
output = [] | |
while line = @r.gets | |
output << line | |
end | |
@r.close | |
output.join.strip.should == string | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment