proteus 0.9.0
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/COPYING +674 -0
- data/README +88 -0
- data/Rakefile +33 -0
- data/bin/pro +189 -0
- data/lib/ClassParser.rb +84 -0
- data/lib/ComponentClass.rb +51 -0
- data/lib/ComponentInstance.rb +76 -0
- data/lib/DefinitionHelper.rb +157 -0
- data/lib/DefinitionParser.rb +107 -0
- data/lib/Facade.rb +116 -0
- data/lib/FileHelper.rb +80 -0
- data/lib/InputParser.rb +241 -0
- data/lib/InstanceParser.rb +65 -0
- data/lib/InstanceProxy.rb +100 -0
- data/lib/PropertyHash.rb +64 -0
- data/lib/TemplateRenderer.rb +128 -0
- data/lib/exceptions.rb +50 -0
- data/test/spec/ClassParser_spec.rb +314 -0
- data/test/spec/ComponentClass_spec.rb +44 -0
- data/test/spec/ComponentInstance_spec.rb +50 -0
- data/test/spec/DefinitionHelper_spec.rb +134 -0
- data/test/spec/DefinitionParser_spec.rb +236 -0
- data/test/spec/Facade_spec.rb +44 -0
- data/test/spec/FileHelper_spec.rb +113 -0
- data/test/spec/InputParser_spec.rb +424 -0
- data/test/spec/InstanceParser_spec.rb +125 -0
- data/test/spec/TemplateRenderer_spec.rb +54 -0
- data/test/spec/lib/NS1/TestComponent10.def +4 -0
- data/test/spec/lib/NS1/TestComponent11.def +4 -0
- data/test/spec/lib/NS1/TestComponent4.def +4 -0
- data/test/spec/lib/NS1/TestComponent5.def +4 -0
- data/test/spec/lib/NS1/TestComponent8.def +4 -0
- data/test/spec/lib/NS1/TestComponent9.def +4 -0
- data/test/spec/lib/NS2/TestComponent6.def +4 -0
- data/test/spec/lib/TestComponent1.def +4 -0
- data/test/spec/lib/TestComponent3.def +4 -0
- data/test/spec/test_lib_dir1/File1.def +0 -0
- data/test/spec/test_lib_dir1/File3.def +0 -0
- data/test/spec/test_lib_dir1/NS1/File4.def +0 -0
- data/test/spec/test_lib_dir1/NS1/NS2/File5.def +0 -0
- data/test/spec/test_lib_dir2/File1.def +0 -0
- data/test/spec/test_lib_dir2/File2.def +0 -0
- metadata +113 -0
data/lib/FileHelper.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
################################################################################
|
2
|
+
# FileHelper.rb
|
3
|
+
#
|
4
|
+
# Provides functions for locating and handling files.
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# (C) Copyright 2009 William Madden
|
7
|
+
#
|
8
|
+
# This file is part of Proteus.
|
9
|
+
#
|
10
|
+
# Proteus is free software: you can redistribute it and/or modify it under the
|
11
|
+
# terms of the GNU General Public License as published by the Free Software
|
12
|
+
# Foundation, either version 3 of the License, or (at your option) any later
|
13
|
+
# version.
|
14
|
+
#
|
15
|
+
# Proteus is distributed in the hope that it will be useful, but WITHOUT ANY
|
16
|
+
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
17
|
+
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU General Public License along with
|
20
|
+
# Proteus. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
################################################################################
|
22
|
+
|
23
|
+
|
24
|
+
module Proteus
|
25
|
+
|
26
|
+
class FileHelper
|
27
|
+
|
28
|
+
# The default path to search for definitions
|
29
|
+
DEFAULT_PATH = File.expand_path( File.join(File.dirname(__FILE__), 'defs') )
|
30
|
+
|
31
|
+
#---------------------------------------------------------------------------
|
32
|
+
#
|
33
|
+
# Methods
|
34
|
+
#
|
35
|
+
#---------------------------------------------------------------------------
|
36
|
+
|
37
|
+
#
|
38
|
+
# Find a file on the path.
|
39
|
+
#
|
40
|
+
# target: the file to search for
|
41
|
+
# path: the path (standard UNIX path variable) to search
|
42
|
+
#
|
43
|
+
# @return Returns the path to the file.
|
44
|
+
#
|
45
|
+
def self.find_file( target, path = nil )
|
46
|
+
path = path || DEFAULT_PATH
|
47
|
+
|
48
|
+
path = path.split(':')
|
49
|
+
|
50
|
+
for filepath in path
|
51
|
+
|
52
|
+
candidate = File.join( filepath, target )
|
53
|
+
|
54
|
+
if ( File.file?(candidate) )
|
55
|
+
return candidate
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
return nil
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Find a definition file.
|
65
|
+
#
|
66
|
+
# class_path: the full path of the class, including all namespaces
|
67
|
+
#
|
68
|
+
def self.find_definition( class_path, path = nil )
|
69
|
+
path = path || DEFAULT_PATH
|
70
|
+
|
71
|
+
file_path = class_path.join('/') + '.def'
|
72
|
+
|
73
|
+
# Search the PATH for the file
|
74
|
+
return self.find_file( file_path, path )
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
data/lib/InputParser.rb
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
################################################################################
|
2
|
+
# InputParser.rb
|
3
|
+
#
|
4
|
+
# Parses input YAML and returns instances.
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# (C) Copyright 2009 William Madden
|
7
|
+
#
|
8
|
+
# This file is part of Proteus.
|
9
|
+
#
|
10
|
+
# Proteus is free software: you can redistribute it and/or modify it under the
|
11
|
+
# terms of the GNU General Public License as published by the Free Software
|
12
|
+
# Foundation, either version 3 of the License, or (at your option) any later
|
13
|
+
# version.
|
14
|
+
#
|
15
|
+
# Proteus is distributed in the hope that it will be useful, but WITHOUT ANY
|
16
|
+
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
17
|
+
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU General Public License along with
|
20
|
+
# Proteus. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
################################################################################
|
22
|
+
|
23
|
+
require File.expand_path( File.join(File.dirname(__FILE__), 'DefinitionHelper.rb') )
|
24
|
+
require File.expand_path( File.join(File.dirname(__FILE__), 'ComponentInstance.rb') )
|
25
|
+
require File.expand_path( File.join(File.dirname(__FILE__), 'InstanceParser.rb') )
|
26
|
+
require File.expand_path( File.join(File.dirname(__FILE__), 'exceptions.rb') )
|
27
|
+
|
28
|
+
module Proteus
|
29
|
+
|
30
|
+
#
|
31
|
+
# Parses input YAML.
|
32
|
+
#
|
33
|
+
class InputParser
|
34
|
+
|
35
|
+
# A regex defining valid component identifiers
|
36
|
+
@@COMPONENT_RE = /^([a-zA-Z_0-9]+:)*([A-Z][a-zA-Z_0-9]*)$/
|
37
|
+
|
38
|
+
#---------------------------------------------------------------------------
|
39
|
+
#
|
40
|
+
# Constructor
|
41
|
+
#
|
42
|
+
#---------------------------------------------------------------------------
|
43
|
+
|
44
|
+
def initialize( instance_parser = nil, definition_helper = nil )
|
45
|
+
|
46
|
+
@instance_parser = instance_parser
|
47
|
+
@definition_helper = definition_helper
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
#---------------------------------------------------------------------------
|
52
|
+
#
|
53
|
+
# Properties
|
54
|
+
#
|
55
|
+
#---------------------------------------------------------------------------
|
56
|
+
|
57
|
+
public
|
58
|
+
|
59
|
+
attr_accessor :instance_parser, :definition_helper
|
60
|
+
|
61
|
+
#---------------------------------------------------------------------------
|
62
|
+
#
|
63
|
+
# Methods
|
64
|
+
#
|
65
|
+
#---------------------------------------------------------------------------
|
66
|
+
|
67
|
+
public
|
68
|
+
|
69
|
+
#------------------------------
|
70
|
+
# parse_yaml
|
71
|
+
#------------------------------
|
72
|
+
|
73
|
+
#
|
74
|
+
# Parses yaml and returns the document tree.
|
75
|
+
#
|
76
|
+
def parse_yaml( yaml, current_ns = nil )
|
77
|
+
|
78
|
+
case
|
79
|
+
when yaml.is_a?( Array ):
|
80
|
+
# Parse each node it contains and return the resultant array
|
81
|
+
return parse_yaml_seq( yaml, current_ns )
|
82
|
+
|
83
|
+
when yaml.is_a?( Hash ):
|
84
|
+
return parse_yaml_map( yaml, current_ns )
|
85
|
+
|
86
|
+
when yaml.nil?:
|
87
|
+
return parse_yaml_nil()
|
88
|
+
|
89
|
+
else
|
90
|
+
return parse_yaml_scalar( yaml, current_ns )
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
#------------------------------
|
96
|
+
# parse_instance
|
97
|
+
#------------------------------
|
98
|
+
|
99
|
+
#
|
100
|
+
# Parses the values of a component instance.
|
101
|
+
#
|
102
|
+
def parse_instance( instance, current_ns = nil )
|
103
|
+
|
104
|
+
# Parse its properties
|
105
|
+
for property in instance.properties
|
106
|
+
instance.properties[ property[0] ] =
|
107
|
+
parse_yaml( property[1], current_ns )
|
108
|
+
end
|
109
|
+
|
110
|
+
# Parse its children
|
111
|
+
instance.children.length.times do |i|
|
112
|
+
instance.children[i] = parse_yaml( instance.children[i], current_ns )
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
#------------------------------
|
118
|
+
# parse_component_id
|
119
|
+
#------------------------------
|
120
|
+
|
121
|
+
#
|
122
|
+
# Parses a component identifier for the class path.
|
123
|
+
#
|
124
|
+
def parse_component_id( component_id )
|
125
|
+
return component_id.split(':')
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
#------------------------------
|
131
|
+
# parse_yaml_seq
|
132
|
+
#------------------------------
|
133
|
+
|
134
|
+
#
|
135
|
+
# Parses a YAML sequence (Array) returning the resultant array.
|
136
|
+
#
|
137
|
+
def parse_yaml_seq( yaml, current_ns )
|
138
|
+
|
139
|
+
return yaml.map { |elem| parse_yaml(elem, current_ns) }
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
#------------------------------
|
144
|
+
# parse_yaml_map
|
145
|
+
#------------------------------
|
146
|
+
|
147
|
+
#
|
148
|
+
# Parses a YAML map (Hash) returning a component or a hash.
|
149
|
+
#
|
150
|
+
def parse_yaml_map( yaml, current_ns )
|
151
|
+
|
152
|
+
# If the hash has only one element and it's a valid component name,
|
153
|
+
# parse it as a component.
|
154
|
+
|
155
|
+
if yaml.length == 1 and @@COMPONENT_RE === yaml.keys.first
|
156
|
+
|
157
|
+
# Parse the value mapped to the key
|
158
|
+
value = parse_yaml( yaml.values.first, current_ns )
|
159
|
+
|
160
|
+
# Parse the component
|
161
|
+
begin
|
162
|
+
return parse_component( yaml.keys.first, value, current_ns )
|
163
|
+
rescue Exceptions::DefinitionUnavailable
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
# Otherwise return the hash, parsing each value.
|
169
|
+
return yaml.inject({}) do |acc, pair|
|
170
|
+
acc[pair[0]] = parse_yaml( pair[1], current_ns )
|
171
|
+
acc
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
#------------------------------
|
177
|
+
# parse_yaml_scalar
|
178
|
+
#------------------------------
|
179
|
+
|
180
|
+
#
|
181
|
+
# Parses a YAML scalar.
|
182
|
+
#
|
183
|
+
def parse_yaml_scalar( yaml, current_ns )
|
184
|
+
|
185
|
+
if @@COMPONENT_RE === yaml then
|
186
|
+
begin
|
187
|
+
return parse_component( yaml, nil, current_ns )
|
188
|
+
rescue Exceptions::DefinitionUnavailable
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
return yaml
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
#------------------------------
|
197
|
+
# parse_yaml_nil
|
198
|
+
#------------------------------
|
199
|
+
|
200
|
+
#
|
201
|
+
# Parses a nil value.
|
202
|
+
#
|
203
|
+
def parse_yaml_nil()
|
204
|
+
|
205
|
+
return nil
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
#------------------------------
|
210
|
+
# parse_component
|
211
|
+
#------------------------------
|
212
|
+
|
213
|
+
#
|
214
|
+
# Parses a component.
|
215
|
+
#
|
216
|
+
# component_id: a component identifier (e.g. HTML:div)
|
217
|
+
# yaml: the YAML describing the instance
|
218
|
+
#
|
219
|
+
def parse_component( component_id, yaml, current_ns )
|
220
|
+
|
221
|
+
result = ComponentInstance.new
|
222
|
+
|
223
|
+
# Parse the id for namespaces and type
|
224
|
+
class_path = parse_component_id( component_id )
|
225
|
+
|
226
|
+
# Get the class of the component
|
227
|
+
result.kind = @definition_helper.get_class( class_path, current_ns )
|
228
|
+
|
229
|
+
# Parse the YAML into the instance
|
230
|
+
@instance_parser.parse_yaml( yaml, result )
|
231
|
+
|
232
|
+
# Parse the values of the instance
|
233
|
+
parse_instance( result, current_ns )
|
234
|
+
|
235
|
+
return result
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
################################################################################
|
2
|
+
# InstanceParser.rb
|
3
|
+
#
|
4
|
+
# Responsible for interpreting YAML for component instances.
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# (C) Copyright 2009 William Madden
|
7
|
+
#
|
8
|
+
# This file is part of Proteus.
|
9
|
+
#
|
10
|
+
# Proteus is free software: you can redistribute it and/or modify it under the
|
11
|
+
# terms of the GNU General Public License as published by the Free Software
|
12
|
+
# Foundation, either version 3 of the License, or (at your option) any later
|
13
|
+
# version.
|
14
|
+
#
|
15
|
+
# Proteus is distributed in the hope that it will be useful, but WITHOUT ANY
|
16
|
+
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
17
|
+
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU General Public License along with
|
20
|
+
# Proteus. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
################################################################################
|
22
|
+
|
23
|
+
require File.expand_path( File.join(File.dirname(__FILE__), 'ComponentInstance.rb') )
|
24
|
+
|
25
|
+
module Proteus
|
26
|
+
|
27
|
+
class InstanceParser
|
28
|
+
|
29
|
+
@@CHILDREN = "children"
|
30
|
+
|
31
|
+
#---------------------------------------------------------------------------
|
32
|
+
#
|
33
|
+
# Methods
|
34
|
+
#
|
35
|
+
#---------------------------------------------------------------------------
|
36
|
+
|
37
|
+
public
|
38
|
+
|
39
|
+
#
|
40
|
+
# Interprets pre-parsed yaml and returns the loaded component instance.
|
41
|
+
#
|
42
|
+
def parse_yaml( yaml, instance = nil )
|
43
|
+
result = instance || ComponentInstance.new
|
44
|
+
|
45
|
+
case
|
46
|
+
when yaml.is_a?( Array ):
|
47
|
+
result.children = yaml
|
48
|
+
|
49
|
+
when yaml.is_a?( Hash ):
|
50
|
+
result.properties.merge!( yaml )
|
51
|
+
result.children = result.properties.delete(@@CHILDREN) || []
|
52
|
+
|
53
|
+
when yaml.nil?:
|
54
|
+
return result
|
55
|
+
|
56
|
+
else
|
57
|
+
result.children = [yaml]
|
58
|
+
end
|
59
|
+
|
60
|
+
return result
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
################################################################################
|
2
|
+
# InstanceProxy.rb
|
3
|
+
#
|
4
|
+
# Provides the environment for rendering templates.
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# (C) Copyright 2009 William Madden
|
7
|
+
#
|
8
|
+
# This file is part of Proteus.
|
9
|
+
#
|
10
|
+
# Proteus is free software: you can redistribute it and/or modify it under the
|
11
|
+
# terms of the GNU General Public License as published by the Free Software
|
12
|
+
# Foundation, either version 3 of the License, or (at your option) any later
|
13
|
+
# version.
|
14
|
+
#
|
15
|
+
# Proteus is distributed in the hope that it will be useful, but WITHOUT ANY
|
16
|
+
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
17
|
+
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU General Public License along with
|
20
|
+
# Proteus. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
################################################################################
|
22
|
+
|
23
|
+
require File.expand_path( File.join(File.dirname(__FILE__), 'PropertyHash.rb') )
|
24
|
+
|
25
|
+
|
26
|
+
module Proteus
|
27
|
+
|
28
|
+
#
|
29
|
+
# Provides the environment for rendering templates.
|
30
|
+
#
|
31
|
+
class InstanceProxy
|
32
|
+
|
33
|
+
#---------------------------------------------------------------------------
|
34
|
+
#
|
35
|
+
# Constructor
|
36
|
+
#
|
37
|
+
#---------------------------------------------------------------------------
|
38
|
+
|
39
|
+
def initialize( renderer, instance )
|
40
|
+
@renderer = renderer
|
41
|
+
@instance = instance
|
42
|
+
|
43
|
+
@kind = @instance.kind
|
44
|
+
@properties = @instance.final_properties
|
45
|
+
@props = PropertyHash.new( @properties, @renderer )
|
46
|
+
@children = @instance.children
|
47
|
+
end
|
48
|
+
|
49
|
+
#---------------------------------------------------------------------------
|
50
|
+
#
|
51
|
+
# Properties
|
52
|
+
#
|
53
|
+
#---------------------------------------------------------------------------
|
54
|
+
|
55
|
+
public
|
56
|
+
|
57
|
+
attr_accessor :renderer, :instance, :kind, :properties, :props, :children
|
58
|
+
|
59
|
+
#---------------------------------------------------------------------------
|
60
|
+
#
|
61
|
+
# Methods
|
62
|
+
#
|
63
|
+
#---------------------------------------------------------------------------
|
64
|
+
|
65
|
+
public
|
66
|
+
|
67
|
+
#
|
68
|
+
# Returns the binding in the scope of the proxy instance.
|
69
|
+
#
|
70
|
+
def instance_env( )
|
71
|
+
return binding()
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Redirects missing method calls to the property hash.
|
76
|
+
#
|
77
|
+
def method_missing(m, *args)
|
78
|
+
@props[ m.to_s ]
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# Returns the next child, or nil.
|
83
|
+
#
|
84
|
+
def next_child
|
85
|
+
if @_last_child_index.nil?
|
86
|
+
@last_child = nil
|
87
|
+
@_last_child_index = 0
|
88
|
+
return renderer.render( children[0] )
|
89
|
+
end
|
90
|
+
|
91
|
+
@last_child = children[ @_last_child_index ]
|
92
|
+
@_last_child_index += 1
|
93
|
+
|
94
|
+
return renderer.render( children[ @_last_child_index ] )
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|