CRUDtree 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.rdoc +42 -0
- data/lib/crudtree.rb +3 -0
- data/lib/crudtree/generator.rb +86 -0
- data/lib/crudtree/helper.rb +19 -0
- data/lib/crudtree/interface.rb +14 -0
- data/lib/crudtree/interface/usher.rb +43 -0
- data/lib/crudtree/interface/usher/rack.rb +40 -0
- data/lib/crudtree/tree.rb +3 -0
- data/lib/crudtree/tree/endnode.rb +40 -0
- data/lib/crudtree/tree/master.rb +20 -0
- data/lib/crudtree/tree/node.rb +121 -0
- data/test/helper/suite/lib/generator.rb +44 -0
- data/test/helper/suite/lib/integration.rb +9 -0
- data/test/helper/suite/lib/interface/blackbox.rb +36 -0
- data/test/setup.rb +6 -0
- data/test/suite/lib/generator.rb +218 -0
- data/test/suite/lib/integration.rb +33 -0
- data/test/suite/lib/interface/blackbox.rb +132 -0
- data/test/suite/lib/interface/usher.rb +55 -0
- data/test/suite/lib/interface/usher/rack.rb +90 -0
- data/test/suite/lib/tree/endnode.rb +27 -0
- data/test/suite/lib/tree/master.rb +9 -0
- data/test/suite/lib/tree/node.rb +91 -0
- metadata +77 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Simon Hafner aka Tass
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
= CRUDtree
|
2
|
+
|
3
|
+
== Summary
|
4
|
+
|
5
|
+
A resource helper mainly for usher, but may be adapted for other routers as
|
6
|
+
well.
|
7
|
+
|
8
|
+
== See
|
9
|
+
|
10
|
+
Usher:: http://github.com/joshbuddy/usher
|
11
|
+
IRC:: #rango@irc.freenode.net
|
12
|
+
Baretest:: http://github.com/apeiros/baretest
|
13
|
+
|
14
|
+
== Terminology
|
15
|
+
|
16
|
+
Master:: The main body, only one per Usher instance as well.
|
17
|
+
Node:: You attach other Nodes or EndNodes as subnodes here.
|
18
|
+
EndNode:: A route endpoint.
|
19
|
+
|
20
|
+
== Usage
|
21
|
+
|
22
|
+
=== as Tinkerer
|
23
|
+
|
24
|
+
CRUDtree::Interface.for(:usher_rack, rango: true).add_helper(CRUDtree::Interface::Helper)
|
25
|
+
|
26
|
+
Usher::Interface.for(:rack) do
|
27
|
+
node(klass: Posts) do
|
28
|
+
sub(type: :member, call: :show, rest: :get)
|
29
|
+
sub(type: :collection, call: :index, rest: :get)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
=== As Dev
|
34
|
+
|
35
|
+
CRUDtree::Interface.for(:usher_rack, rango: true)
|
36
|
+
|
37
|
+
Usher::Interface.for(:rack) do
|
38
|
+
resource(klass: Posts) do # the resource helper will include a bunch of default routes
|
39
|
+
member(call: :show, rest: :get)
|
40
|
+
collection(call: :index, rest: :get)
|
41
|
+
end
|
42
|
+
end
|
data/lib/crudtree.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
module CRUDtree
|
2
|
+
class Generator
|
3
|
+
def initialize(master)
|
4
|
+
@master = master
|
5
|
+
@model_to_node = {}
|
6
|
+
@master.nodes.each {|node| add_node_models(node) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def generate(resource, *names)
|
10
|
+
if resource.is_a? Symbol
|
11
|
+
names << resource
|
12
|
+
node = @master
|
13
|
+
url = ""
|
14
|
+
else
|
15
|
+
node, identifiers = find_node(resource)
|
16
|
+
url = generate_url_from_node(node, identifiers)
|
17
|
+
end
|
18
|
+
url << generate_from_sub(node, names) unless names.empty?
|
19
|
+
url
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def find_node(resource)
|
24
|
+
case nodes = @model_to_node[resource.class]
|
25
|
+
when Node
|
26
|
+
[nodes, [resource.send(nodes.identifier)]]
|
27
|
+
when Array
|
28
|
+
valid_nodes = {}
|
29
|
+
nodes.each do |node|
|
30
|
+
identifiers = identifiers_to_node(resource, node)
|
31
|
+
valid_nodes[node] = identifiers if identifiers
|
32
|
+
end
|
33
|
+
parents = valid_nodes.keys.map(&:parents).flatten
|
34
|
+
valid_nodes.reject!{|node, identifiers| parents.include?(node)}
|
35
|
+
case valid_nodes.size
|
36
|
+
when 1
|
37
|
+
valid_nodes.first
|
38
|
+
when 0
|
39
|
+
raise(NoNode, "No node found for #{resource}.")
|
40
|
+
else
|
41
|
+
raise(NoUniqueNode, "No unique node found for #{resource}.")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_node_models(node)
|
47
|
+
@model_to_node[node.model] = if target_node = @model_to_node[node.model]
|
48
|
+
([target_node] << node).flatten
|
49
|
+
else
|
50
|
+
node
|
51
|
+
end
|
52
|
+
node.nodes.each { |subnode|
|
53
|
+
add_node_models(subnode)
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def generate_url_from_node(node, identifiers)
|
58
|
+
(node.parents.reverse + [node]).map {|parent|
|
59
|
+
"/#{parent.path}/#{identifiers.shift}"
|
60
|
+
}.join
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [Array] with [String] of identifiers or false if the model is invalid
|
64
|
+
# for this node
|
65
|
+
def identifiers_to_node(model, node, identifiers = [])
|
66
|
+
return false unless node.model == model.class
|
67
|
+
identifiers << model.send(node.identifier).to_s
|
68
|
+
unless node.parent_is_master?
|
69
|
+
identifiers_to_node(model.send(node.parent_call), node.parent, identifiers) or return false
|
70
|
+
end
|
71
|
+
identifiers.reverse
|
72
|
+
end
|
73
|
+
|
74
|
+
def generate_from_sub(node, names)
|
75
|
+
name = names.shift
|
76
|
+
sub = node.subs.find{|sub| sub.name == name} or raise(ArgumentError, "No subnode found on #{node} with name of #{name}.")
|
77
|
+
url = "/#{sub.path}"
|
78
|
+
url << generate_from_sub(sub, names) unless names.empty?
|
79
|
+
url
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class InvalidPath < StandardError; end
|
84
|
+
class NoUniqueNode < StandardError; end
|
85
|
+
class NoNode < StandardError; end
|
86
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module CRUDtree
|
2
|
+
module Interface
|
3
|
+
module Helper
|
4
|
+
def resource(params, &resource_block)
|
5
|
+
node(params) do
|
6
|
+
collection(call: :index, rest: :get)
|
7
|
+
collection(call: :new, rest: :get)
|
8
|
+
collection(call: :create, rest: :post, path: "")
|
9
|
+
member(call: :show, rest: :get)
|
10
|
+
member(call: :edit, rest: :get)
|
11
|
+
member(call: :update, rest: :put, path: "")
|
12
|
+
member(call: :delete, rest: :get)
|
13
|
+
member(call: :destroy, rest: :delete, path: "")
|
14
|
+
eval(&resource_block) if resource_block
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative "../interface"
|
2
|
+
module CRUDtree
|
3
|
+
module Interface
|
4
|
+
module Usher
|
5
|
+
# Integration part
|
6
|
+
|
7
|
+
def master_params
|
8
|
+
master.params
|
9
|
+
end
|
10
|
+
|
11
|
+
def master
|
12
|
+
@master ||= Master.new
|
13
|
+
end
|
14
|
+
|
15
|
+
# Logic part
|
16
|
+
|
17
|
+
def node(params, &block)
|
18
|
+
node = master.node(params, &block)
|
19
|
+
compile_node("", node)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def compile_node(pre_path, node)
|
24
|
+
paths = node.paths.map {|p| "#{pre_path}/#{p}"}
|
25
|
+
paths.each do |path|
|
26
|
+
node.subnodes.each do |subnode|
|
27
|
+
compile_subnode(path, subnode)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def compile_subnode(pre_path, subnode)
|
33
|
+
case subnode
|
34
|
+
when EndNode
|
35
|
+
compile_endnode(pre_path, subnode)
|
36
|
+
when Node
|
37
|
+
compile_node("#{pre_path}/:#{subnode.identifier}", subnode)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative '../usher'
|
2
|
+
|
3
|
+
module CRUDtree
|
4
|
+
module Interface
|
5
|
+
module Usher
|
6
|
+
module Rack
|
7
|
+
include CRUDtree::Interface::Usher
|
8
|
+
|
9
|
+
def self.attach
|
10
|
+
::Usher::Interface.class_for(:rack).send(:include, self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.add_helper(helper)
|
14
|
+
include helper
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def compile_endnode(pre_path, endnode)
|
19
|
+
conditions = {}
|
20
|
+
conditions.merge!({request_method: endnode.rest.to_s.upcase}) if endnode.rest
|
21
|
+
method_call = [endnode.call]
|
22
|
+
method_call.unshift(master_params[:dispatcher])
|
23
|
+
# Here we call usher.
|
24
|
+
path(compile_path(pre_path, endnode), conditions: conditions).to(endnode.parent.klass.send(*method_call))
|
25
|
+
end
|
26
|
+
|
27
|
+
def compile_path(pre_path, endnode)
|
28
|
+
node = endnode.parent
|
29
|
+
compiled_path = [pre_path]
|
30
|
+
compiled_path << ":#{node.identifier}" if endnode.type == :member
|
31
|
+
compiled_path << "#{endnode.path}" unless endnode.path.empty?
|
32
|
+
compiled_path.join('/')
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
CRUDtree::Interface.register(:usher_rack, CRUDtree::Interface::Usher::Rack)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module CRUDtree
|
2
|
+
class EndNode
|
3
|
+
# The params Hash takes the following keys:
|
4
|
+
#
|
5
|
+
# :type
|
6
|
+
# may either be member or collection
|
7
|
+
#
|
8
|
+
# :path
|
9
|
+
# path to this endnode - you can use
|
10
|
+
# join
|
11
|
+
# or
|
12
|
+
# join/:date/:foo/:whatever
|
13
|
+
# the interface will handle those parameters.
|
14
|
+
# Defaults to call.to_s
|
15
|
+
#
|
16
|
+
# :rest
|
17
|
+
# which REST method should match this route. Defaults to nil, aka all.
|
18
|
+
#
|
19
|
+
# :call
|
20
|
+
# The method to be called if this route is matched. Required.
|
21
|
+
#
|
22
|
+
# :name
|
23
|
+
# The name of this route, used for generating. Symbol.
|
24
|
+
# Defaults to call
|
25
|
+
#
|
26
|
+
def initialize(parent, params)
|
27
|
+
@type = params[:type] if [:member, :collection].include? params[:type]
|
28
|
+
raise ArgumentError, "Invalid type: #{params[:type]}" unless @type
|
29
|
+
@call = params[:call] or raise ArgumentError, "No call given."
|
30
|
+
@path = params[:path] || @call.to_s
|
31
|
+
raise ArgumentError, "No path given." unless @path
|
32
|
+
@rest = params[:rest]
|
33
|
+
@name = params[:name] || @call
|
34
|
+
@parent = parent
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :type, :path, :rest, :call, :name, :parent
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CRUDtree
|
2
|
+
class Master
|
3
|
+
|
4
|
+
# Use :rango => true if you're using rango
|
5
|
+
def initialize(params = {})
|
6
|
+
@nodes = []
|
7
|
+
@params = {dispatcher: :dispatcher}.merge(params)
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :nodes
|
11
|
+
attr_accessor :mapping, :params
|
12
|
+
|
13
|
+
alias_method :subs, :nodes
|
14
|
+
|
15
|
+
def node(params, &block)
|
16
|
+
@nodes << new_node = Node.new(self, params, &block)
|
17
|
+
new_node
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module CRUDtree
|
2
|
+
class Node
|
3
|
+
# The params Hash takes the following keys:
|
4
|
+
#
|
5
|
+
# :klass
|
6
|
+
# The object where to send the method that is returned by the router.
|
7
|
+
# Mostly a class, therefore it's called 'class_name'. Defaults to nil,
|
8
|
+
# but the interface may complain. You have been warned ;).
|
9
|
+
# May be used by the interface as needed (Rango wants Class.send
|
10
|
+
# :dispatcher, :send_method)
|
11
|
+
#
|
12
|
+
# :identifier
|
13
|
+
# The identifier used to identify a resource, aka /user/:name instead of
|
14
|
+
# /user/:id (default).
|
15
|
+
#
|
16
|
+
# :default_collection
|
17
|
+
# The collection that is called when nothing is given. Defaults to :index.
|
18
|
+
#
|
19
|
+
# :default_member
|
20
|
+
# The member which is chosen when no method is given. Defaults to :show.
|
21
|
+
#
|
22
|
+
# :paths
|
23
|
+
# Specify the path(s) you want to call this resource with.
|
24
|
+
# Defaults to klass.to_s.downcase
|
25
|
+
# The first one is used for generation.
|
26
|
+
#
|
27
|
+
# Options used for generating
|
28
|
+
#
|
29
|
+
# :model
|
30
|
+
# The name of the model. Needed. We don't do magic here.
|
31
|
+
#
|
32
|
+
# :parent_call
|
33
|
+
# The method to call on the model object to get its parent (for nested
|
34
|
+
# resources). Defaults to :model.downcase of the parent.
|
35
|
+
#
|
36
|
+
# :name
|
37
|
+
# Symbol used to identify the node when generating a collection route.
|
38
|
+
# Defaults to Klass.to_s.downcase.to_sym
|
39
|
+
#
|
40
|
+
def initialize(parent, params, &block)
|
41
|
+
@klass = params[:klass]
|
42
|
+
@identifier = params[:identifier] || :id
|
43
|
+
@default_collection = params[:default_collection] || :index
|
44
|
+
@default_member = params[:default_member] || :show
|
45
|
+
@paths = if params[:paths]
|
46
|
+
[params[:paths]].flatten
|
47
|
+
elsif params[:klass]
|
48
|
+
[params[:klass].to_s.downcase.split("::").last]
|
49
|
+
else
|
50
|
+
raise ArgumentError, "No paths given"
|
51
|
+
end
|
52
|
+
@subnodes = []
|
53
|
+
@parent = parent
|
54
|
+
# default routes
|
55
|
+
@subnodes.unshift(EndNode.new(self, type: :member, call: :show, path: "", rest: :get))
|
56
|
+
@subnodes.unshift(EndNode.new(self, type: :collection, call: :index, path: "", rest: :get))
|
57
|
+
# generating
|
58
|
+
unless @model = params[:model]
|
59
|
+
raise(ArgumentError, "No model given.")
|
60
|
+
end
|
61
|
+
@parent_call = if params[:parent_call]
|
62
|
+
params[:parent_call]
|
63
|
+
elsif ! parent_is_master?
|
64
|
+
parent.model.to_s.split('::').last.downcase
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
@name = params[:name] || klass.to_s.downcase.to_sym
|
69
|
+
block ? instance_eval(&block) : raise(ArgumentError, "No block given.")
|
70
|
+
end
|
71
|
+
|
72
|
+
attr_reader :klass, :identifier, :default_collection, :default_member, :paths, :parent, :subnodes, :model, :parent_call, :name
|
73
|
+
|
74
|
+
# Creates a new End and attaches it to this Node.
|
75
|
+
def endnode(params)
|
76
|
+
@subnodes << EndNode.new(self, params)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Creates a new endnode with type member. See Endnode.
|
80
|
+
def member(params)
|
81
|
+
endnode(params.merge({type: :member}))
|
82
|
+
end
|
83
|
+
|
84
|
+
# Creates a new endnode with type collection. See EndNode.
|
85
|
+
def collection(params)
|
86
|
+
endnode(params.merge({type: :collection}))
|
87
|
+
end
|
88
|
+
|
89
|
+
def node(params, &block)
|
90
|
+
@subnodes << Node.new(self, params, &block)
|
91
|
+
end
|
92
|
+
|
93
|
+
def parents
|
94
|
+
[find_parent(self)].flatten[0..-2]
|
95
|
+
end
|
96
|
+
|
97
|
+
def nodes
|
98
|
+
subnodes.select{|subnode| subnode.is_a? Node}
|
99
|
+
end
|
100
|
+
|
101
|
+
def endnodes
|
102
|
+
subnodes.select{|subnode| subnode.is_a? EndNode}
|
103
|
+
end
|
104
|
+
|
105
|
+
def parent_is_master?
|
106
|
+
! parent.respond_to? :parent
|
107
|
+
end
|
108
|
+
|
109
|
+
# Duck typing used for generation
|
110
|
+
def path
|
111
|
+
@paths.first
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
def find_parent(node)
|
116
|
+
if node.parent.respond_to? :parent
|
117
|
+
[node.parent, find_parent(node.parent)]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class Model0
|
2
|
+
def id
|
3
|
+
0
|
4
|
+
end
|
5
|
+
end
|
6
|
+
class Model1
|
7
|
+
end
|
8
|
+
class Model2
|
9
|
+
def id
|
10
|
+
2
|
11
|
+
end
|
12
|
+
def model0
|
13
|
+
Model0.new
|
14
|
+
end
|
15
|
+
end
|
16
|
+
class Klass0
|
17
|
+
end
|
18
|
+
class Klass1
|
19
|
+
end
|
20
|
+
class Klass2
|
21
|
+
end
|
22
|
+
|
23
|
+
class Mod0
|
24
|
+
def id
|
25
|
+
0
|
26
|
+
end
|
27
|
+
end
|
28
|
+
class Mod1
|
29
|
+
def id
|
30
|
+
1
|
31
|
+
end
|
32
|
+
def mod0
|
33
|
+
Mod0.new
|
34
|
+
end
|
35
|
+
end
|
36
|
+
class Mod2
|
37
|
+
def id
|
38
|
+
2
|
39
|
+
end
|
40
|
+
def initialize(parent = Mod0)
|
41
|
+
instance_variable_set("@#{parent.to_s.downcase}", parent.new)
|
42
|
+
end
|
43
|
+
attr_accessor :mod0, :mod1, :mod2
|
44
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
def results_in(path, klass, call, params)
|
2
|
+
klass.expects(:dispatcher).with(call).returns(:yeah!)
|
3
|
+
to_mock = mock('to')
|
4
|
+
to_mock.expects(:to).with(:yeah!).returns(true)
|
5
|
+
Usher::Interface.class_for(:rack).any_instance.expects(:path).with(path, params).returns(to_mock)
|
6
|
+
end
|
7
|
+
|
8
|
+
module Usher; module Interface; class Rack;
|
9
|
+
include CRUDtree::Interface::Usher::Rack
|
10
|
+
def initialize(app = nil, options = nil, &block)
|
11
|
+
instance_eval(&block) if block
|
12
|
+
end
|
13
|
+
end; end; end
|
14
|
+
class TestObj0; end
|
15
|
+
class TestObj1; end
|
16
|
+
class TestObj2; end
|
17
|
+
|
18
|
+
def default_routes(number=0)
|
19
|
+
default_route(TestObj0)
|
20
|
+
default_route(TestObj1, "/testobj0/:id") if number > 0
|
21
|
+
default_route(TestObj2, "/testobj0/:id/testobj1/:id") if number > 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def default_route(klass, pre_path=nil)
|
25
|
+
results_in("#{pre_path}/#{klass.to_s.downcase}", klass, :index, :conditions => {:request_method => "GET"})
|
26
|
+
results_in("#{pre_path}/#{klass.to_s.downcase}/:id", klass, :show, :conditions => {:request_method => "GET"})
|
27
|
+
end
|
28
|
+
module Usher
|
29
|
+
module Interface
|
30
|
+
def self.class_for(interface)
|
31
|
+
Rack
|
32
|
+
end
|
33
|
+
class Rack
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/test/setup.rb
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
BareTest.suite do
|
3
|
+
|
4
|
+
suite "CRUDtree" do
|
5
|
+
|
6
|
+
suite "Generator" do
|
7
|
+
|
8
|
+
suite "#generate_url_from_node" do
|
9
|
+
|
10
|
+
setup :node, "a simple node" do
|
11
|
+
@node = Node.new(nil, :paths => ["foo"], klass: Object, model: Object ){:foo}
|
12
|
+
@path = "/foo/23"
|
13
|
+
@identifiers = [23]
|
14
|
+
end
|
15
|
+
|
16
|
+
setup :node, "a node with multiple parents" do
|
17
|
+
master = Master.new
|
18
|
+
master.node(klass: Object, model: Object, paths: ["foo"]) do
|
19
|
+
node(klass: Object, model: Object, paths: ["bar"]) do
|
20
|
+
node(klass: Object, model: Object, paths: ["baz"]) {:foo}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
@node = master.nodes.first.nodes.first.nodes.first
|
24
|
+
@path = "/foo/1/bar/2/baz/3"
|
25
|
+
@identifiers = [1,2,3]
|
26
|
+
end
|
27
|
+
|
28
|
+
assert ":node goes to the right path" do
|
29
|
+
equal(@path, CRUDtree::Generator.allocate.send(:generate_url_from_node, @node, @identifiers))
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
suite "#model_to_node" do
|
35
|
+
|
36
|
+
setup do
|
37
|
+
class TestObj0; end
|
38
|
+
class TestObj1; end
|
39
|
+
end
|
40
|
+
|
41
|
+
setup :master, "a simple master" do
|
42
|
+
master = CRUDtree::Master.new
|
43
|
+
master.node(klass: Object, model: ::TestObj0) {:foo}
|
44
|
+
@generator = CRUDtree::Generator.new(master)
|
45
|
+
@node = master.nodes.first
|
46
|
+
@model = ::TestObj0
|
47
|
+
end
|
48
|
+
|
49
|
+
setup :master, "a complex master" do
|
50
|
+
master = CRUDtree::Master.new
|
51
|
+
master.node(klass: Object, model: ::TestObj1){
|
52
|
+
node(klass: Object, model: ::TestObj0){:foo}
|
53
|
+
}
|
54
|
+
@generator = CRUDtree::Generator.new(master)
|
55
|
+
@node = master.nodes.first.nodes.first
|
56
|
+
@model = ::TestObj0
|
57
|
+
end
|
58
|
+
|
59
|
+
setup :master, "a master with duplicate models" do
|
60
|
+
master = CRUDtree::Master.new
|
61
|
+
master.node(klass: Object, model: TestObj1){
|
62
|
+
node(klass: Object, model: ::TestObj0){:foo}
|
63
|
+
node(klass: Object, model: ::TestObj0){:foo}
|
64
|
+
}
|
65
|
+
@generator = CRUDtree::Generator.new(master)
|
66
|
+
@node = master.nodes.first.nodes
|
67
|
+
@model = ::TestObj0
|
68
|
+
end
|
69
|
+
|
70
|
+
assert "The right model is found on :master." do
|
71
|
+
equal(@node, @generator.instance_variable_get(:@model_to_node)[@model])
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
suite "node finding" do
|
77
|
+
|
78
|
+
suite "without duplicates" do
|
79
|
+
|
80
|
+
setup do
|
81
|
+
@master = CRUDtree::Master.new
|
82
|
+
end
|
83
|
+
|
84
|
+
setup :master, "a simple master" do
|
85
|
+
@node = @master.node(klass: Klass0, model: Model0){:foo}
|
86
|
+
@resource = Model0.new
|
87
|
+
@valid = [[Model0.new, @node, ["0"]]]
|
88
|
+
@invalid = [[Model2.new, @node], [Model1.new, @node]]
|
89
|
+
end
|
90
|
+
|
91
|
+
setup :master, "a complex master" do
|
92
|
+
@master.node(klass: Klass0, model: Model0) do
|
93
|
+
node(klass: Klass1, model: Model1){:foo}
|
94
|
+
node(klass: Klass2, model: Model2){:foo}
|
95
|
+
end
|
96
|
+
@node = @master.nodes.first.nodes.last
|
97
|
+
@resource = Model2.new
|
98
|
+
@valid = [[Model2.new, @node, ["0","2"]], [Model0.new, @master.nodes.first, ["0"]]]
|
99
|
+
@invalid = [[Model0.new, @node], [Model1.new, @node]]
|
100
|
+
end
|
101
|
+
|
102
|
+
assert "#identifiers_returns the corret identifiers with :master" do
|
103
|
+
generator = CRUDtree::Generator.new(@master)
|
104
|
+
@valid.all?{|model, node, ary| generator.send(:identifiers_to_node, model, node) == ary}
|
105
|
+
end
|
106
|
+
|
107
|
+
assert "#identifiers returns false invalid with :master" do
|
108
|
+
generator = CRUDtree::Generator.new(@master)
|
109
|
+
@invalid.all?{|model, node| ! generator.send(:identifiers_to_node, model, node)}
|
110
|
+
end
|
111
|
+
|
112
|
+
assert "#find_node gets the correct node from :master" do
|
113
|
+
same(@node, CRUDtree::Generator.new(@master).send(:find_node, @resource).first)
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
suite "with duplicates" do
|
119
|
+
|
120
|
+
setup do
|
121
|
+
@master = Master.new
|
122
|
+
@master.node(klass: Klass0, model: Mod0) do
|
123
|
+
node(klass: Klass1, model: Mod1){:foo}
|
124
|
+
node(klass: Klass2, model: Mod2) do
|
125
|
+
node(klass: Klass2, model: Mod2){:foo}
|
126
|
+
end
|
127
|
+
end
|
128
|
+
@generator = CRUDtree::Generator.new(@master)
|
129
|
+
end
|
130
|
+
|
131
|
+
setup :node, "nested node" do
|
132
|
+
@node = @master.nodes.first.nodes.last.nodes.first
|
133
|
+
@resource = Mod2.new(Mod2)
|
134
|
+
@identifier = %w(0 2 2)
|
135
|
+
end
|
136
|
+
|
137
|
+
setup :node, "first node" do
|
138
|
+
@node = @master.nodes.first.nodes.last
|
139
|
+
@resource = Mod2.new(Mod0)
|
140
|
+
@identifier = %w(0 2)
|
141
|
+
end
|
142
|
+
|
143
|
+
assert "#identifiers_to_node returns an Array of identifiers for the :node" do
|
144
|
+
equal(@identifier, @generator.send(:identifiers_to_node, @resource, @node))
|
145
|
+
end
|
146
|
+
|
147
|
+
assert "#find_node gets :node based on the model" do
|
148
|
+
same(@node, @generator.send(:find_node, @resource).first)
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
suite "#generate_from_sub" do
|
156
|
+
|
157
|
+
setup do
|
158
|
+
@foo = OpenStruct.new(:name => :foo, :path => "foo")
|
159
|
+
@bar = OpenStruct.new(:name => :bar, :path => "bar")
|
160
|
+
end
|
161
|
+
|
162
|
+
setup :names, "one name" do
|
163
|
+
@node = OpenStruct.new(:subs => [@foo, @bar])
|
164
|
+
@names = [:foo]
|
165
|
+
@path = "/foo"
|
166
|
+
end
|
167
|
+
|
168
|
+
setup :names, "stacked names" do
|
169
|
+
@node = OpenStruct.new(:subs => [OpenStruct.new(:subs => [@foo, @bar], :name => :foo, :path => "foo"), @bar])
|
170
|
+
@names = [:foo, :bar]
|
171
|
+
@path = "/foo/bar"
|
172
|
+
end
|
173
|
+
|
174
|
+
assert "generates the correct url from :names" do
|
175
|
+
equal @path, Generator.allocate.send(:generate_from_sub, @node, @names)
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
suite "blackbox" do
|
181
|
+
|
182
|
+
setup do
|
183
|
+
@master = Master.new
|
184
|
+
@master.node(klass: Klass0, model: Mod0) do
|
185
|
+
node(klass: Klass1, model: Mod1){:foo}
|
186
|
+
node(klass: Klass2, model: Mod2) do
|
187
|
+
node(klass: Klass2, model: Mod2){:foo}
|
188
|
+
end
|
189
|
+
end
|
190
|
+
@generator = CRUDtree::Generator.new(@master)
|
191
|
+
end
|
192
|
+
|
193
|
+
setup :model, "model for the nested node" do
|
194
|
+
@resource = Mod2.new(Mod2)
|
195
|
+
@path = "/klass0/0/klass2/2/klass2/2"
|
196
|
+
end
|
197
|
+
|
198
|
+
setup :model, "model for the first node" do
|
199
|
+
@resource = Mod2.new(Mod0)
|
200
|
+
@path = "/klass0/0/klass2/2"
|
201
|
+
end
|
202
|
+
|
203
|
+
setup :model, "model for the simplest node" do
|
204
|
+
@resource = Mod0.new
|
205
|
+
@path = "/klass0/0"
|
206
|
+
end
|
207
|
+
|
208
|
+
assert "#generate" do
|
209
|
+
equal(@path, @generator.generate(@resource))
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'crudtree/interface/usher/rack'
|
2
|
+
module Usher
|
3
|
+
module Interface
|
4
|
+
class Rack
|
5
|
+
def initialize(app = nil, options = nil, &blk)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
BareTest.suite do
|
12
|
+
|
13
|
+
suite "CRUDtree" do
|
14
|
+
|
15
|
+
suite "integartion" do
|
16
|
+
|
17
|
+
suite "inclusion" do
|
18
|
+
|
19
|
+
setup do
|
20
|
+
CRUDtree::Interface.for(:usher_rack)
|
21
|
+
end
|
22
|
+
|
23
|
+
assert "the module gets included and the methods are avaible" do
|
24
|
+
Usher::Interface.class_for(:rack).new.respond_to? :node
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
BareTest.suite "CRUDtree" do
|
2
|
+
|
3
|
+
suite "blackbox" do
|
4
|
+
|
5
|
+
setup :tree, "a simple tree" do
|
6
|
+
@block = proc {
|
7
|
+
node(model: Object, klass: TestObj0) do
|
8
|
+
collection(call: :index, rest: :get)
|
9
|
+
end
|
10
|
+
}
|
11
|
+
results_in("/testobj0/index", TestObj0, :index, :conditions => {:request_method => "GET"})
|
12
|
+
# default routes
|
13
|
+
default_routes
|
14
|
+
end
|
15
|
+
|
16
|
+
setup :tree, "a nested tree" do
|
17
|
+
@block = proc {
|
18
|
+
node(model: Object, klass: TestObj0) do
|
19
|
+
node(model: Object, klass: TestObj1) do
|
20
|
+
member(call: :show, rest: :get)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
}
|
24
|
+
results_in("/testobj0/:id/testobj1/:id/show", TestObj1, :show, :conditions => {:request_method => "GET"})
|
25
|
+
# default routes
|
26
|
+
default_routes(1)
|
27
|
+
end
|
28
|
+
|
29
|
+
setup :tree, "a twice nested tree" do
|
30
|
+
@block = proc {
|
31
|
+
node(model: Object, klass: TestObj0) do
|
32
|
+
node(model: Object, klass: TestObj1) do
|
33
|
+
node(model: Object, klass: TestObj2) do
|
34
|
+
collection(call: :create, rest: :post)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
}
|
39
|
+
results_in("/testobj0/:id/testobj1/:id/testobj2/create", TestObj2, :create, :conditions => {:request_method => "POST"})
|
40
|
+
# default routes
|
41
|
+
default_routes(2)
|
42
|
+
end
|
43
|
+
|
44
|
+
setup :tree, "a tree with some subnodes" do
|
45
|
+
@block = proc {
|
46
|
+
node(model: Object, klass: TestObj0) do
|
47
|
+
collection(call: :index, rest: :get)
|
48
|
+
member(call: :show, rest: :get)
|
49
|
+
member(call: :update, path: "edit", rest: :put)
|
50
|
+
end
|
51
|
+
}
|
52
|
+
results_in("/testobj0/index", TestObj0, :index, :conditions => {:request_method => "GET"})
|
53
|
+
results_in("/testobj0/:id/edit", TestObj0, :update, :conditions => {:request_method => "PUT"})
|
54
|
+
results_in("/testobj0/:id/show", TestObj0, :show, :conditions => {:request_method => "GET"})
|
55
|
+
# default routes
|
56
|
+
default_routes
|
57
|
+
end
|
58
|
+
|
59
|
+
setup :tree, "a nested tree with some subnodes" do
|
60
|
+
@block = proc {
|
61
|
+
node(model: Object, klass: TestObj0) do
|
62
|
+
member(call: :show, rest: :get)
|
63
|
+
node(model: Object, klass: TestObj1) do
|
64
|
+
collection(call: :index, rest: :get)
|
65
|
+
member(call: :show, rest: :get)
|
66
|
+
member(call: :update, path: "edit", rest: :put)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
}
|
70
|
+
results_in("/testobj0/:id/show", TestObj0, :show, :conditions => {:request_method => "GET"})
|
71
|
+
results_in("/testobj0/:id/testobj1/index", TestObj1, :index, :conditions => {:request_method => "GET"})
|
72
|
+
results_in("/testobj0/:id/testobj1/:id/show", TestObj1, :show, :conditions => {:request_method => "GET"})
|
73
|
+
results_in("/testobj0/:id/testobj1/:id/edit", TestObj1, :update, :conditions => {:request_method => "PUT"})
|
74
|
+
# default routes
|
75
|
+
default_routes(1)
|
76
|
+
end
|
77
|
+
|
78
|
+
setup :tree, "a tree with multiple paths" do
|
79
|
+
@block = proc {
|
80
|
+
node(model: Object, paths: ["test", "foo", "bar"], klass: TestObj0) do
|
81
|
+
collection(call: :index, rest: :get)
|
82
|
+
end
|
83
|
+
}
|
84
|
+
results_in("/test/index", TestObj0, :index, :conditions => {:request_method => "GET"})
|
85
|
+
results_in("/foo/index", TestObj0, :index, :conditions => {:request_method => "GET"})
|
86
|
+
results_in("/bar/index", TestObj0, :index, :conditions => {:request_method => "GET"})
|
87
|
+
# default routes
|
88
|
+
results_in("/test", TestObj0, :index, :conditions => {:request_method => "GET"})
|
89
|
+
results_in("/foo", TestObj0, :index, :conditions => {:request_method => "GET"})
|
90
|
+
results_in("/bar", TestObj0, :index, :conditions => {:request_method => "GET"})
|
91
|
+
results_in("/test/:id", TestObj0, :show, :conditions => {:request_method => "GET"})
|
92
|
+
results_in("/foo/:id", TestObj0, :show, :conditions => {:request_method => "GET"})
|
93
|
+
results_in("/bar/:id", TestObj0, :show, :conditions => {:request_method => "GET"})
|
94
|
+
end
|
95
|
+
|
96
|
+
setup :tree, "a nested tree with multiple paths" do
|
97
|
+
@block = proc {
|
98
|
+
node(model: Object, paths: ["foo", "bar"], klass: TestObj0) do
|
99
|
+
collection(call: :index, rest: :get)
|
100
|
+
node(model: Object, paths: ["test", "baz"], klass: TestObj1) do
|
101
|
+
member(call: :edit, rest: :get)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
}
|
105
|
+
results_in("/foo/index", TestObj0, :index, :conditions => {:request_method => "GET"})
|
106
|
+
results_in("/bar/index", TestObj0, :index, :conditions => {:request_method => "GET"})
|
107
|
+
results_in("/foo/:id/test/:id/edit", TestObj1, :edit, :conditions => {:request_method => "GET"})
|
108
|
+
results_in("/bar/:id/test/:id/edit", TestObj1, :edit, :conditions => {:request_method => "GET"})
|
109
|
+
results_in("/foo/:id/baz/:id/edit", TestObj1, :edit, :conditions => {:request_method => "GET"})
|
110
|
+
results_in("/bar/:id/baz/:id/edit", TestObj1, :edit, :conditions => {:request_method => "GET"})
|
111
|
+
# default routes
|
112
|
+
results_in("/foo", TestObj0, :index, :conditions => {:request_method => "GET"})
|
113
|
+
results_in("/bar", TestObj0, :index, :conditions => {:request_method => "GET"})
|
114
|
+
results_in("/foo/:id", TestObj0, :show, :conditions => {:request_method => "GET"})
|
115
|
+
results_in("/bar/:id", TestObj0, :show, :conditions => {:request_method => "GET"})
|
116
|
+
results_in("/foo/:id/test", TestObj1, :index, :conditions => {:request_method => "GET"})
|
117
|
+
results_in("/bar/:id/test", TestObj1, :index, :conditions => {:request_method => "GET"})
|
118
|
+
results_in("/foo/:id/baz", TestObj1, :index, :conditions => {:request_method => "GET"})
|
119
|
+
results_in("/bar/:id/baz", TestObj1, :index, :conditions => {:request_method => "GET"})
|
120
|
+
results_in("/foo/:id/test/:id", TestObj1, :show, :conditions => {:request_method => "GET"})
|
121
|
+
results_in("/bar/:id/test/:id", TestObj1, :show, :conditions => {:request_method => "GET"})
|
122
|
+
results_in("/foo/:id/baz/:id", TestObj1, :show, :conditions => {:request_method => "GET"})
|
123
|
+
results_in("/bar/:id/baz/:id", TestObj1, :show, :conditions => {:request_method => "GET"})
|
124
|
+
end
|
125
|
+
|
126
|
+
assert "compilation of :tree" do
|
127
|
+
Usher::Interface.class_for(:rack).new(&@block)
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'crudtree/interface/usher'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module CRUDtree::Interface::Usher
|
5
|
+
public :compile_subnode, :compile_node
|
6
|
+
extend self
|
7
|
+
end
|
8
|
+
|
9
|
+
BareTest.suite "CRUDtree" do
|
10
|
+
|
11
|
+
suite "interface" do
|
12
|
+
|
13
|
+
suite "usher" do
|
14
|
+
|
15
|
+
suite "#compile_subnode" do
|
16
|
+
|
17
|
+
setup :subnode, "Node" do
|
18
|
+
@pre_path = "/foo"
|
19
|
+
@subnode = Node.new(nil, klass: Object, paths: "foo", model: Object) {:foo}
|
20
|
+
CRUDtree::Interface::Usher.expects(:compile_node).with("/foo/:id", @subnode).returns(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
setup :subnode, "EndNode" do
|
24
|
+
@pre_path = ""
|
25
|
+
@subnode = EndNode.allocate
|
26
|
+
CRUDtree::Interface::Usher.expects(:compile_subnode).with(@pre_path, @subnode).returns(true)
|
27
|
+
end
|
28
|
+
|
29
|
+
assert "Compilation with a :subnode as subnode" do
|
30
|
+
CRUDtree::Interface::Usher.compile_subnode(@pre_path, @subnode)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
suite "#compile_node" do
|
36
|
+
|
37
|
+
setup do
|
38
|
+
@subnode = Object.new
|
39
|
+
@pre_path = "/baz"
|
40
|
+
@node = OpenStruct.new(paths: ["foo", "bar"], subnodes: [@subnode])
|
41
|
+
CRUDtree::Interface::Usher.expects(:compile_subnode).with("/baz/foo", @subnode).returns(true)
|
42
|
+
CRUDtree::Interface::Usher.expects(:compile_subnode).with("/baz/bar", @subnode).returns(true)
|
43
|
+
end
|
44
|
+
|
45
|
+
assert "compilation" do
|
46
|
+
CRUDtree::Interface::Usher.compile_node(@pre_path, @node)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'crudtree/interface/usher/rack'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
BareTest.suite "CRUDtree" do
|
7
|
+
|
8
|
+
suite "interface" do
|
9
|
+
|
10
|
+
suite "usher" do
|
11
|
+
|
12
|
+
suite "rack" do
|
13
|
+
|
14
|
+
setup do
|
15
|
+
module CRUDtree::Interface::Usher::Rack
|
16
|
+
public :compile_path
|
17
|
+
extend self
|
18
|
+
end
|
19
|
+
|
20
|
+
class TestObj < Object; end
|
21
|
+
class TestObj2 < Object; end
|
22
|
+
class Cont1 < Object; end
|
23
|
+
class Cont2 < Object; end
|
24
|
+
end
|
25
|
+
|
26
|
+
suite "#compile_path" do
|
27
|
+
|
28
|
+
setup :subnode, "a simple member subnode" do
|
29
|
+
@pre_path = ""
|
30
|
+
@node = OpenStruct.new(klass: TestObj, identifier: :id, paths: "testobj")
|
31
|
+
@subnode = EndNode.new(@node, type: :member, call: :foo, name: "foo")
|
32
|
+
@path = "/testobj/:id/foo"
|
33
|
+
@params = {conditions: {}}
|
34
|
+
@send = [:foo]
|
35
|
+
@master_params = {}
|
36
|
+
end
|
37
|
+
|
38
|
+
setup :subnode, "a more complex collection subnode" do
|
39
|
+
@pre_path = "/bar"
|
40
|
+
@node = OpenStruct.new(klass: TestObj, identifier: :id, paths: "testobj")
|
41
|
+
@subnode = EndNode.new(@node, type: :collection, call: :foo, name: "foo")
|
42
|
+
@path = "/bar/testobj/foo"
|
43
|
+
@params = {conditions: {}}
|
44
|
+
@send = [:dispatcher, :foo]
|
45
|
+
@master_params = {rango: true}
|
46
|
+
end
|
47
|
+
|
48
|
+
setup :subnode, "a nested collection subnode" do
|
49
|
+
@pre_path = ""
|
50
|
+
@node1 = Node.new(nil, klass: Cont1, identifier: :id, paths: "cont1", model: Object){:foo}
|
51
|
+
@node2 = Node.new(@node1, klass: TestObj, model: Object){:foo}
|
52
|
+
@subnode = EndNode.new(@node2, type: :collection, call: :foo, name: "foo", model: Object)
|
53
|
+
@path = "/cont1/:id/testobj/foo"
|
54
|
+
@params = {conditions: {}}
|
55
|
+
@send = [:dispatcher, :foo]
|
56
|
+
@master_params = {rango: true}
|
57
|
+
end
|
58
|
+
|
59
|
+
setup :subnode, "a nested member subnode" do
|
60
|
+
@pre_path = ""
|
61
|
+
@node1 = Node.new(nil, klass: Cont1, identifier: :id, paths: "cont1", model: Object){:foo}
|
62
|
+
@node2 = Node.new(@node1, klass: TestObj, model: Object){:foo}
|
63
|
+
@subnode = EndNode.new(@node2, type: :member, call: :foo, name: "foo")
|
64
|
+
@path = "/cont1/:id/testobj/:id/foo"
|
65
|
+
@params = {conditions: {}}
|
66
|
+
@send = [:foo]
|
67
|
+
@master_params = {}
|
68
|
+
end
|
69
|
+
|
70
|
+
setup :foo, "Foo" do
|
71
|
+
TestObj.expects(:send).with(*@send).returns(:yeah)
|
72
|
+
TestObj2.any_instance.expects(:to).with(:yeah)
|
73
|
+
CRUDtree::Interface::Usher::Rack.expects(:master_params).returns(@master_params)
|
74
|
+
CRUDtree::Interface::Usher::Rack.expects(:path).with(@path, @params).returns(TestObj2.new)
|
75
|
+
end
|
76
|
+
|
77
|
+
assert "compilaton with :subnode" do
|
78
|
+
CRUDtree::Interface::Usher::Rack.compile_path(@pre_path, @subnode)
|
79
|
+
true
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
BareTest.suite "CRUDtree" do
|
2
|
+
|
3
|
+
suite "tree" do
|
4
|
+
|
5
|
+
suite "EndNode" do
|
6
|
+
|
7
|
+
suite "initialize" do
|
8
|
+
|
9
|
+
assert ":type should only accept :member or :collection" do
|
10
|
+
raises(ArgumentError) {EndNode.new(nil, type: :foo, call: :foo)}
|
11
|
+
end
|
12
|
+
|
13
|
+
assert ":call should not accept an empty argument" do
|
14
|
+
raises(ArgumentError) {EndNode.new(nil, type: :member, path: "/foo")}
|
15
|
+
end
|
16
|
+
|
17
|
+
assert ":path should default to :call" do
|
18
|
+
EndNode.new(nil, type: :member, call: :foo, name: :foo).path == "foo"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
BareTest.suite "CRUDtree" do
|
2
|
+
|
3
|
+
suite "tree" do
|
4
|
+
|
5
|
+
suite "node" do
|
6
|
+
|
7
|
+
suite "initialize" do
|
8
|
+
|
9
|
+
suite "paths" do
|
10
|
+
|
11
|
+
assert "defaults to the name of the class" do
|
12
|
+
Node.new(nil, klass: Node, model: Object){:foo}.paths == ["node"]
|
13
|
+
end
|
14
|
+
|
15
|
+
assert "raises if no path is given" do
|
16
|
+
raises(ArgumentError) {Node.new(nil, foo: :bar){:foo}}
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
assert "raises if no block is given" do
|
22
|
+
raises(ArgumentError) {Node.new(nil, foo: :bar)}
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
suite "extended subnodes" do
|
28
|
+
|
29
|
+
setup :method, "#member" do
|
30
|
+
@method = :member
|
31
|
+
end
|
32
|
+
|
33
|
+
setup :method, "#collection" do
|
34
|
+
@method = :collection
|
35
|
+
end
|
36
|
+
|
37
|
+
setup :node, "node" do
|
38
|
+
@node = Node.allocate
|
39
|
+
@params = {foo: :bar}
|
40
|
+
@result = @params.merge({type: @method})
|
41
|
+
@node.expects(:endnode).with(@result)
|
42
|
+
end
|
43
|
+
|
44
|
+
assert ":method" do
|
45
|
+
case @method
|
46
|
+
when :member
|
47
|
+
@node.member @params
|
48
|
+
when :collection
|
49
|
+
@node.collection @params
|
50
|
+
end
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
suite "tree walking" do
|
57
|
+
|
58
|
+
setup :master, "a simple master" do
|
59
|
+
@master = Master.new
|
60
|
+
@node = @master.node(klass: Object, model: Object){:foo}
|
61
|
+
@parents = []
|
62
|
+
@children = {}
|
63
|
+
end
|
64
|
+
|
65
|
+
suite "#parents" do
|
66
|
+
|
67
|
+
setup :master, "a more complex master" do
|
68
|
+
@master = Master.new
|
69
|
+
@master.node(klass: Object, model: Object){
|
70
|
+
node(klass: Object, model: Object){
|
71
|
+
node(klass: Object, model: Object){:foo}
|
72
|
+
node(klass: Object, model: Object){:foo}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
@node = @master.nodes.first.nodes.first.nodes.first
|
76
|
+
@parents = [@master.nodes.first.nodes.first,@master.nodes.first]
|
77
|
+
end
|
78
|
+
|
79
|
+
assert "it find the parents in :master" do
|
80
|
+
equal(@node.parents, @parents)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: CRUDtree
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Simon Hafner aka Tass
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain:
|
11
|
+
date: 2010-01-25 00:00:00 +01:00
|
12
|
+
default_executable:
|
13
|
+
dependencies: []
|
14
|
+
|
15
|
+
description: ""
|
16
|
+
email: hafnersimon@gmail.com
|
17
|
+
executables: []
|
18
|
+
|
19
|
+
extensions: []
|
20
|
+
|
21
|
+
extra_rdoc_files: []
|
22
|
+
|
23
|
+
files:
|
24
|
+
- lib/crudtree/generator.rb
|
25
|
+
- lib/crudtree/helper.rb
|
26
|
+
- lib/crudtree/interface/usher/rack.rb
|
27
|
+
- lib/crudtree/interface/usher.rb
|
28
|
+
- lib/crudtree/interface.rb
|
29
|
+
- lib/crudtree/tree/endnode.rb
|
30
|
+
- lib/crudtree/tree/master.rb
|
31
|
+
- lib/crudtree/tree/node.rb
|
32
|
+
- lib/crudtree/tree.rb
|
33
|
+
- lib/crudtree.rb
|
34
|
+
- test/helper/suite/lib/generator.rb
|
35
|
+
- test/helper/suite/lib/integration.rb
|
36
|
+
- test/helper/suite/lib/interface/blackbox.rb
|
37
|
+
- test/setup.rb
|
38
|
+
- test/suite/lib/generator.rb
|
39
|
+
- test/suite/lib/integration.rb
|
40
|
+
- test/suite/lib/interface/blackbox.rb
|
41
|
+
- test/suite/lib/interface/usher/rack.rb
|
42
|
+
- test/suite/lib/interface/usher.rb
|
43
|
+
- test/suite/lib/tree/endnode.rb
|
44
|
+
- test/suite/lib/tree/master.rb
|
45
|
+
- test/suite/lib/tree/node.rb
|
46
|
+
- LICENSE
|
47
|
+
- README.rdoc
|
48
|
+
has_rdoc: true
|
49
|
+
homepage: http://github.com/Tass/CRUDtree
|
50
|
+
licenses: []
|
51
|
+
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "1.9"
|
62
|
+
version:
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
version:
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.3.5
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: A resource helper mainly for usher, but may be adapted for other routers as well.
|
76
|
+
test_files: []
|
77
|
+
|