Skip to content
Browse files

New API for strategies.

Instead of passing cumbersome options to initializers, one must now
use a middleware-inspired system: tree.use :my_strategy. More
information on the Strategy module's documentation.
  • Loading branch information...
1 parent 96e7e34 commit a12a01f2de541a2b582d6929c48e8689a652de31 @chikamichi committed Jul 14, 2011
View
29 lib/jumoku.rb
@@ -39,28 +39,29 @@
#
module Jumoku
# core implementations
- autoload :Shared, 'jumoku/builders/shared'
- autoload :Extended, 'jumoku/builders/extended'
+ autoload :Shared, 'jumoku/builders/shared'
+ autoload :Extended, 'jumoku/builders/extended'
# branch types
- autoload :UndirectedBranch, 'jumoku/support/branch'
- autoload :DirectedBranch, 'jumoku/support/branch'
+ autoload :UndirectedBranch, 'jumoku/support/branch'
+ autoload :DirectedBranch, 'jumoku/support/branch'
# tree builders
- autoload :RawUndirectedTreeBuilder, 'jumoku/builders/raw_undirected_tree'
- autoload :RawDirectedTreeBuilder, 'jumoku/builders/raw_directed_tree'
- autoload :TreeBuilder, 'jumoku/builders/tree'
- autoload :ArborescenceBuilder, 'jumoku/builders/arborescence'
+ autoload :RawUndirectedTreeBuilder, 'jumoku/builders/raw_undirected_tree'
+ autoload :RawDirectedTreeBuilder, 'jumoku/builders/raw_directed_tree'
+ autoload :TreeBuilder, 'jumoku/builders/tree'
+ autoload :ArborescenceBuilder, 'jumoku/builders/arborescence'
# tree classes
- autoload :RawDirectedTree, 'jumoku/classes/tree_classes'
- autoload :RawUndirectedTree, 'jumoku/classes/tree_classes'
- autoload :Tree, 'jumoku/classes/tree_classes'
- autoload :Arborescence, 'jumoku/classes/tree_classes'
+ autoload :RawDirectedTree, 'jumoku/classes/tree_classes'
+ autoload :RawUndirectedTree, 'jumoku/classes/tree_classes'
+ autoload :Tree, 'jumoku/classes/tree_classes'
+ autoload :Arborescence, 'jumoku/classes/tree_classes'
# strategies
- autoload :EdgeLabeling, 'jumoku/strategies/edge_labeling'
- EdgeLabeling.autoload :Simple, 'jumoku/strategies/edge_labeling/simple'
+ autoload :Strategies, 'jumoku/strategies'
+ Strategies.autoload :EdgeLabelingBackend, 'jumoku/strategies/edge_labeling'
+ Strategies.autoload :SimpleEdgeLabeling, 'jumoku/strategies/edge_labeling/simple'
# support
require 'jumoku/support/ruby_compatibility'
View
2 lib/jumoku/builders/extended.rb
@@ -298,7 +298,7 @@ def branches_among?(*maybe_branches)
end
alias has_branches_among? branches_among?
- # Number of nodes.
+ # Number of nodes. Just `#nodes.size` really.
#
# @return [Integer]
#
View
10 lib/jumoku/builders/raw_directed_tree.rb
@@ -23,14 +23,8 @@ module RawDirectedTreeBuilder
#
def initialize(*params)
super(*params) # Delegates to Plexus.
- args = (params.pop if params.last.is_a? Hash) || {}
- @_options = args
- strategies = _extract_strategies(args)
-
- class << self; self; end.module_eval do
- strategies.each { |strategy| include strategy }
- alias has_branch? has_arc?
- end
+ @_options = (params.pop if params.last.is_a? Hash) || {}
+ _delay { alias has_branch? has_arc? }
end
# Checks whether the tree is *really* a valid tree, that is if the
View
12 lib/jumoku/builders/raw_undirected_tree.rb
@@ -28,16 +28,8 @@ module RawUndirectedTreeBuilder
#
def initialize(*params)
super(*params) # Delegates to Plexus.
- args = (params.pop if params.last.is_a? Hash) || {}
- @_options = args
- strategies = _extract_strategies(args)
-
- super(*params) # Delegates to Plexus.
-
- class << self; self; end.module_eval do
- strategies.each { |strategy| include strategy }
- alias has_branch? has_edge?
- end
+ @_options = (params.pop if params.last.is_a? Hash) || {}
+ _delay { alias has_branch? has_edge? }
end
# Checks whether the tree is *really* a valid tree, that is if the
View
17 lib/jumoku/builders/shared.rb
@@ -3,12 +3,11 @@ module Jumoku
# builders: {RawUndirectedTreeBuilder} and {RawDirectedTreeBuilder}.
#
module Shared
- STRATEGIES = [:edge_labeling, :node_labeling]
-
def self.included(base)
base.class_eval do
# Late aliasing as it references methods provided by Plexus modules.
alias has_node? has_vertex?
+ include Jumoku::Strategies
end
end
@@ -211,16 +210,10 @@ def _clone
self.class.new(self)
end
- def _extract_strategies(options)
- options = options.dup.select! { |k,v| STRATEGIES.include?(k) } || options.dup
- options.inject([]) do |strategies, (k,v)|
- begin
- strategies << Jumoku.const_get(k.to_s.constantize).const_get(v.to_s.constantize)
- strategies
- rescue NameError # silently ignored
- strategies
- end
- end
+ # Some code chunks must be module evaled at runtime.
+ #
+ def _delay
+ class << self; self; end.module_eval { yield }
end
end
end
View
32 lib/jumoku/strategies.rb
@@ -0,0 +1,32 @@
+module Jumoku
+ # Strategies are decorators implemented as mixins which taint a tree object
+ # with new or extended features. For instance, the `SimpleEdgeLabeling`
+ # strategy alters the way new nodes and branches are added to a tree,
+ # enforcing labeling of edges with increasing integers, `Binary` enforces
+ # a tree to grow as a binary tree, etc.
+ #
+ # It is easy to develop your own decorators and `use` them.
+ #
+ module Strategies
+ # Activate a strategy.
+ #
+ # @param [#to_s, Module] strategy strategy's name, either as a module
+ # namespace (like `Strategies::SimpleEdgeLabeling`) or a symbol (like
+ # `:simple_edge_labeling`)
+ #
+ def use(strategy)
+ strategy = catch(:unknown_strategy) do
+ begin
+ if strategy.is_a?(Symbol) || strategy.is_a?(String)
+ strategy = Strategies.const_get(strategy.to_s.constantize)
+ end
+ rescue NameError
+ throw :unknown_strategy, nil
+ end
+ strategy
+ end
+ extend strategy unless strategy.nil?
+ end
+ alias strategy use
+ end
+end
View
14 lib/jumoku/strategies/edge_labeling.rb
@@ -1,14 +1,14 @@
module Jumoku
- # Edge labeling strategies are concerned with the way edges or arcs are
- # labeled. Simple labeling schemes are based on indexing with increasing
- # integers, whereas some other strategies elaborate on notions such as
- # weight or symetry.
- #
- module EdgeLabeling
+ module Strategies
+ # Edge labeling strategies are concerned with the way edges or arcs are
+ # labeled. Simple labeling schemes are based on indexing with increasing
+ # integers, whereas some other strategies elaborate on notions such as
+ # weight or symetry.
+ #
# This module provides basic implementation for the common ground used
# by custom strategies.
#
- module Backend
+ module EdgeLabelingBackend
# Sort edges by the provided block's logic. The block takes edge as
# parameter, and this method delegates to Enumerable#sort_by for
# sorting edges. Return unsorted edges list if no block is provided.
View
6 lib/jumoku/strategies/edge_labeling/simple.rb
@@ -1,5 +1,5 @@
module Jumoku
- module EdgeLabeling
+ module Strategies
# A simple edge labeling strategy: as new nodes are added, new edges are
# assigned increasing integers. Removed edges do not trigger reindexing,
# so for a tree with n nodes, the labeling set is ||n|| but indexes are
@@ -8,8 +8,8 @@ module EdgeLabeling
# This simple strategy allows for using simple search algorithms as well
# for simple ordering schemes.
#
- module Simple
- include EdgeLabeling::Backend
+ module SimpleEdgeLabeling
+ include Strategies::EdgeLabelingBackend
attr_accessor :next_simple_edge_label_number
View
2 lib/jumoku/version.rb
@@ -1,6 +1,6 @@
module Jumoku
MAJOR = 0
MINOR = 2
- PATCH = 4
+ PATCH = 5
VERSION = [MAJOR, MINOR, PATCH].join('.')
end
View
6 spec/strategies/simple_edge_labeling.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe EdgeLabeling::Simple do
- let(:tree) { Tree.new(:edge_labeling => :simple) }
- let(:arbo) { Arborescence.new(:edge_labeling => :simple) }
+describe Strategies::SimpleEdgeLabeling do
+ let(:tree) { Tree.new.use Strategies::SimpleEdgeLabeling }
+ let(:arbo) { Arborescence.new.use :simple_edge_labeling }
describe 'a tree with simple edge labeling' do
it "should label its edges with increasing integers when new nodes are added or removed" do

0 comments on commit a12a01f

Please sign in to comment.
Something went wrong with that request. Please try again.