Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

. Polishing

  • Loading branch information...
commit 2b0ff332f1c5c1c30de0dcdb91491ded4cc6ecd9 1 parent c940148
Kaspar Schiess authored
113 lib/floor_manager/employee.rb
View
@@ -3,115 +3,7 @@
require 'blankslate'
module FloorManager::Employee
- class DSL < BlankSlate
- # A proxy that is the receiver of #set and #append in a construct like this:
- #
- # one :spy do
- # relationship.set :gun
- # end
- #
- class AssocProxy < Struct.new(:employee, :field)
- def set(*create_args)
- employee.add_attribute AttributeAction::AssocSet.new(field, create_args)
- end
- def append(*create_args)
- employee.add_attribute AttributeAction::AssocAppend.new(field, create_args)
- end
- end
-
- def initialize(employee, &block)
- @employee = employee
-
- instance_eval(&block)
- end
-
- def method_missing(sym, *args, &block)
- if args.size == 1
- # Immediate attribute
- value = args.first
- @employee.add_attribute AttributeAction::Immediate.new(sym, value)
- elsif block
- # Lazy attribute
- @employee.add_attribute AttributeAction::Block.new(sym, block)
- elsif args.empty?
- # Maybe: #set / #append proxy?
- AssocProxy.new(@employee, sym)
- else
- super
- end
- end
- end
- module AttributeAction
- # Base class for stored actions.
- class Base
- def initialize(name)
- @name = name
- end
- def set(obj, value)
- if obj.kind_of?(Hash)
- obj[@name] = value
- else
- obj.send("#{@name}=", value)
- end
- end
- def get(obj)
- if obj.kind_of?(Hash)
- obj[@name]
- else
- obj.send(@name)
- end
- end
- end
-
- # Stores the action of producing another employee via a collection proxy
- # stored in field.
- class AssocAppend < Base
- def initialize(field, create_args)
- super field
- @create_args = create_args
- end
- def apply(obj, floor)
- attributes = floor.attrs(*@create_args)
- get(obj).build(attributes)
- end
- end
-
- # Stores the action of producing another employee via the floor and then
- # storing that as a value.
- class AssocSet < Base
- def initialize(field, create_args)
- super field
- @create_args = create_args
- end
- def apply(obj, floor)
- set(obj, floor.create(*@create_args))
- end
- end
-
- # Stores the action of setting an attribute to an immediate value.
- class Immediate < Base
- def initialize(name, value)
- super(name)
- @value = value
- end
- def apply(obj, floor)
- set(obj, @value)
- end
- end
-
- # Stores the action of setting an attribute to the result of a block.
- class Block < Base
- def initialize(name, block)
- super(name)
- @block = block
- end
- def apply(obj, floor)
- set(obj, @block.call(obj, floor))
- end
- end
- end
-
# Base class for employees. No instances of this should be created.
class Base
def self.from_dsl(klass_name, &block)
@@ -202,4 +94,7 @@ def reset
class Template < Base
# Currently empty, see base class
end
-end
+end
+
+require 'floor_manager/employee/dsl'
+require 'floor_manager/employee/attribute_action'
71 lib/floor_manager/employee/attribute_action.rb
View
@@ -0,0 +1,71 @@
+module FloorManager::Employee
+ module AttributeAction
+ # Base class for stored actions.
+ class Base
+ def initialize(name)
+ @name = name
+ end
+ def set(obj, value)
+ if obj.kind_of?(Hash)
+ obj[@name] = value
+ else
+ obj.send("#{@name}=", value)
+ end
+ end
+ def get(obj)
+ if obj.kind_of?(Hash)
+ obj[@name]
+ else
+ obj.send(@name)
+ end
+ end
+ end
+
+ # Stores the action of producing another employee via a collection proxy
+ # stored in field.
+ class AssocAppend < Base
+ def initialize(field, create_args)
+ super field
+ @create_args = create_args
+ end
+ def apply(obj, floor)
+ associated_employee = floor.build(*@create_args)
+ get(obj).build(associated_employee.attributes)
+ end
+ end
+
+ # Stores the action of producing another employee via the floor and then
+ # storing that as a value.
+ class AssocSet < Base
+ def initialize(field, create_args)
+ super field
+ @create_args = create_args
+ end
+ def apply(obj, floor)
+ set(obj, floor.create(*@create_args))
+ end
+ end
+
+ # Stores the action of setting an attribute to an immediate value.
+ class Immediate < Base
+ def initialize(name, value)
+ super(name)
+ @value = value
+ end
+ def apply(obj, floor)
+ set(obj, @value)
+ end
+ end
+
+ # Stores the action of setting an attribute to the result of a block.
+ class Block < Base
+ def initialize(name, block)
+ super(name)
+ @block = block
+ end
+ def apply(obj, floor)
+ set(obj, @block.call(obj, floor))
+ end
+ end
+ end
+end
62 lib/floor_manager/employee/dsl.rb
View
@@ -0,0 +1,62 @@
+module FloorManager::Employee
+ class DSL < BlankSlate
+ # A proxy that is the receiver of #set and #append in a construct like this:
+ #
+ # one :spy do
+ # relationship.set :gun
+ # end
+ #
+ class AssocProxy < Struct.new(:employee, :field)
+ def set(*create_args)
+ employee.add_attribute AttributeAction::AssocSet.new(field, create_args)
+ end
+ def append(*create_args)
+ employee.add_attribute AttributeAction::AssocAppend.new(field, create_args)
+ end
+ end
+
+ def initialize(employee, &block)
+ @employee = employee
+
+ instance_eval(&block)
+ end
+
+ # This method missing handles several magic incantations:
+ #
+ # a) Setting an attribute to a value that is given:
+ #
+ # name 'john'
+ #
+ # b) Setting an attribute to a value that is returned from a block:
+ #
+ # name { |obj, floor| rand()>0.5 ? 'John' : 'Peter' }
+ #
+ # Note that the first argument is the +obj+ under construction (your
+ # model instance) and the second argument is the floor the model is
+ # being constructed in. This is useful for retrieving other objects that
+ # live in the same floor.
+ #
+ # c) Access to the association magic:
+ #
+ # spouse.set :linda
+ # friends.append :frank
+ #
+ # Please see +AssocProxy+ for further explanation on this.
+ #
+ def method_missing(sym, *args, &block)
+ if args.size == 1
+ # Immediate attribute
+ value = args.first
+ @employee.add_attribute AttributeAction::Immediate.new(sym, value)
+ elsif block
+ # Lazy attribute
+ @employee.add_attribute AttributeAction::Block.new(sym, block)
+ elsif args.empty?
+ # Maybe: #set / #append proxy?
+ AssocProxy.new(@employee, sym)
+ else
+ super
+ end
+ end
+ end
+end
14 lib/floor_manager/floor.rb
View
@@ -33,6 +33,20 @@ def initialize
@employees = {}
end
+ # Allows production of new employees by calling their names as methods on
+ # the floor.
+ #
+ # With a definition of
+ #
+ # one :dog do
+ # end
+ #
+ # you could call
+ #
+ # floor.dog
+ #
+ # and get the same as if you had called floor.build :dog
+ #
def method_missing(sym, *args, &block)
if args.size <= 1 && employees.has_key?(sym)
attribute_overrides = {}
2  spec/support/model/spy.rb
View
@@ -6,7 +6,7 @@ class Spy
def self.build(attrs={})
new.tap { |instance|
attrs.each do |a,v|
- if respond_to?("#{a}=")
+ if instance.respond_to?("#{a}=")
instance.send("#{a}=", v)
end
end
9 spec/unit/floor_manager_spec.rb
View
@@ -126,6 +126,7 @@
# has and belongs to many (uses association.create)
enemies.append :black
enemies.append :white
+ enemies.append :green
end
end
@@ -136,10 +137,16 @@
let(:any_spy) { env.spy }
subject { any_spy }
- its(:enemies) { should have(2).entries }
+ its(:enemies) { should have(3).entries }
it "should have green in #opposite" do
any_spy.opposite.should == env.green
end
+ it "should not have recreated a green spy in #enemies" do
+ green2 = any_spy.enemies.select { |s| s.name == 'green' }.first
+ green1 = any_spy.opposite
+
+ green1.should == green2
+ end
end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.