Permalink
Browse files

bug fix: ordering bugs with multiple before/after

  • Loading branch information...
1 parent 547a9ea commit 68d4bf187a31e7f295e72bc318d2e29d55342bbe @moonmaster9000 committed Aug 21, 2012
Showing with 181 additions and 34 deletions.
  1. +0 −1 app/frills/view_context_frill.rb
  2. +122 −12 lib/frill/frill.rb
  3. +3 −1 readme.markdown
  4. +56 −20 spec/frill_spec.rb
@@ -1,6 +1,5 @@
module ViewContextFrill
include Frill
- first
def self.frill? object, controller
object.class_eval do
View
@@ -1,19 +1,19 @@
module Frill
def self.included(base)
- self.decorators << base
+ self.decorators.add base
base.extend ClassMethods
end
def self.decorators
- @decorators ||= []
+ @decorators ||= Graph.new
end
def self.reset!
@decorators = nil
end
def self.decorate object, context
- decorators.each do |d|
+ decorators.sorted_nodes.each do |d|
object.extend d if d.frill? object, context
end
@@ -22,22 +22,132 @@ def self.decorate object, context
module ClassMethods
def before decorator
- move Frill.decorators.index(decorator)
+ Frill.decorators.move_before self, decorator
end
def after decorator
- move(Frill.decorators.index(decorator) + 1)
+ Frill.decorators.move_after self, decorator
end
+ end
+
+ class Graph
+ def initialize
+ @nodes = {}
+ end
+
+ def add label
+ @nodes[label] ||= Node.new label
+ end
+
+ def move_before label1, label2
+ node1 = add label1
+ node2 = add label2
+
+ node1.move_before node2
+ end
+
+ def move_after label1, label2
+ node1 = add label1
+ node2 = add label2
+
+ node1.move_after node2
+ end
+
+ def [](label)
+ @nodes[label]
+ end
+
+ def empty?
+ @nodes.empty?
+ end
+
+ def include? label
+ @nodes.keys.include? label
+ end
+
+ def index label
+ sorted_nodes.index label
+ end
+
+ def sorted_nodes
+ lists = []
+
+ @nodes.values.each do |node|
+ unless lists.include? node.label
+ leaf = node.leaf
+ lists += leaf.to_a
+ end
+ end
- def first
- move 0
+ lists
end
- private
- def move index
- Frill.decorators.delete self
- Frill.decorators.insert index, self
- Frill.decorators.compact!
+ class Node
+ attr_accessor :parent, :child
+ attr_reader :label
+
+ def initialize(label)
+ @label = label
+ @parent = nil
+ @child = nil
+ end
+
+ def move_before node
+ parent_node = node.leaf
+
+ parent_node.child = self
+ self.parent = parent_node
+ end
+
+ def move_after node
+ child_node = node.root
+
+ self.child = child_node
+ child.parent = self
+ end
+
+ def leaf
+ node = nil
+ current_node = self
+
+ until node
+ if current_node.child
+ current_node = current_node.child
+ else
+ node = current_node
+ end
+ end
+
+ node
+ end
+
+ def root
+ current_node = self
+ root_node = nil
+
+ until root_node
+ if current_node.parent
+ current_node = current_node.parent
+ else
+ root_node = current_node
+ end
+ end
+
+ root_node
+ end
+
+ def to_a
+ current_node = self
+
+ list = []
+
+ until current_node == nil
+ list << current_node.label
+ current_node = current_node.parent
+ end
+
+ list
+ end
end
end
end
View
@@ -112,9 +112,11 @@ end
Two things to note: the `HtmlTimestampFrill` is only applicable to
objects that have timestamps _when presented in "html"_. Also, we
-tell `Frill` to decorate after `TimestampFrill` is applied (so that
+tell `Frill` to decorate `after` `TimestampFrill` is applied (so that
`super` in `created_at` returns our `TimestampFrill` response).
+Note that you can also specify decoration dependencies with `before` instead of `after`.
+
Next, in our controller, we need to decorate our objects with frills:
```ruby
View
@@ -7,7 +7,7 @@
describe ".reset" do
before do
- Frill.decorators << Module.new
+ Module.new { include Frill }
Frill.decorators.should_not be_empty
end
@@ -62,46 +62,82 @@ def self.frill? object, context
describe Frill::ClassMethods do
before do
- module Module1
- include Frill
- end
+ module Module2; include Frill; end
+ module Module1; include Frill; end
+ module Module5; include Frill; end
+ module Module4; include Frill; end
+ module Module3; include Frill; end
+ end
- module Module2
- include Frill
- end
+ describe ".before" do
+ it "inserts the current module before the requested module in Frill's list of decorators" do
+ Module5.before Module4
+ Module4.before Module3
+ Module3.before Module2
+ Module2.before Module1
- module Module3
- include Frill
+ Frill.decorators.index(Module5).should be < Frill.decorators.index(Module4)
+ Frill.decorators.index(Module3).should be < Frill.decorators.index(Module2)
+ Frill.decorators.index(Module2).should be < Frill.decorators.index(Module1)
+ Frill.decorators.index(Module4).should be < Frill.decorators.index(Module3)
end
+ end
+ end
+
+ describe Frill::ClassMethods do
+ before do
+ module Module1; include Frill; end
+ module Module2; include Frill; end
+ module Module3; include Frill; end
end
describe ".before" do
it "inserts the current module before the requested module in Frill's list of decorators" do
- Frill.decorators.should == [Module1, Module2, Module3]
+ Frill.decorators.sorted_nodes.should == [Module1, Module2, Module3]
+
+ Module1.before Module2
+ Frill.decorators.sorted_nodes.should == [Module1, Module2, Module3]
- Module2.before Module1
Module3.before Module2
- Frill.decorators.should == [Module3, Module2, Module1]
+ Frill.decorators.sorted_nodes.should == [Module3, Module1, Module2]
end
end
describe ".after" do
it "inserts the current module after the requested module in Frill's list of decorators" do
- Frill.decorators.should == [Module1, Module2, Module3]
+ Frill.decorators.sorted_nodes.should == [Module1, Module2, Module3]
Module1.after Module2
Module3.after Module2
- Frill.decorators.first.should == Module2
- Frill.decorators.last(2).should =~ [Module1, Module3]
+
+ Frill.decorators.sorted_nodes.first.should == Module2
+ Frill.decorators.sorted_nodes.last(2).should =~ [Module1, Module3]
end
end
+ end
- describe ".first" do
- it "inserts the current module at the beginning of the list of Frill's decorators" do
- Frill.decorators.should == [Module1, Module2, Module3]
+ describe Frill::Graph do
+ describe "#add" do
+ it "should add an element to the graph" do
+ g = Frill::Graph.new
+ g.add "hi"
+ g["hi"].should_not be_nil
+ end
+ end
+
+ describe "#move_before(label1, label2)" do
+ it "should move label1 before label2" do
+ g = Frill::Graph.new
+ g.move_before "a", "b"
+ g.sorted_nodes.should == ["a", "b"]
+ end
+ end
- Module2.first
- Frill.decorators.first.should == Module2
+ describe "#move_after(label1, label2)" do
+ it "should move label1 after label2" do
+ g = Frill::Graph.new
+ g.move_after "a", "b"
+ g.sorted_nodes.should == ["b", "a"]
end
end
end

0 comments on commit 68d4bf1

Please sign in to comment.