proteus 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/COPYING +674 -0
  2. data/README +88 -0
  3. data/Rakefile +33 -0
  4. data/bin/pro +189 -0
  5. data/lib/ClassParser.rb +84 -0
  6. data/lib/ComponentClass.rb +51 -0
  7. data/lib/ComponentInstance.rb +76 -0
  8. data/lib/DefinitionHelper.rb +157 -0
  9. data/lib/DefinitionParser.rb +107 -0
  10. data/lib/Facade.rb +116 -0
  11. data/lib/FileHelper.rb +80 -0
  12. data/lib/InputParser.rb +241 -0
  13. data/lib/InstanceParser.rb +65 -0
  14. data/lib/InstanceProxy.rb +100 -0
  15. data/lib/PropertyHash.rb +64 -0
  16. data/lib/TemplateRenderer.rb +128 -0
  17. data/lib/exceptions.rb +50 -0
  18. data/test/spec/ClassParser_spec.rb +314 -0
  19. data/test/spec/ComponentClass_spec.rb +44 -0
  20. data/test/spec/ComponentInstance_spec.rb +50 -0
  21. data/test/spec/DefinitionHelper_spec.rb +134 -0
  22. data/test/spec/DefinitionParser_spec.rb +236 -0
  23. data/test/spec/Facade_spec.rb +44 -0
  24. data/test/spec/FileHelper_spec.rb +113 -0
  25. data/test/spec/InputParser_spec.rb +424 -0
  26. data/test/spec/InstanceParser_spec.rb +125 -0
  27. data/test/spec/TemplateRenderer_spec.rb +54 -0
  28. data/test/spec/lib/NS1/TestComponent10.def +4 -0
  29. data/test/spec/lib/NS1/TestComponent11.def +4 -0
  30. data/test/spec/lib/NS1/TestComponent4.def +4 -0
  31. data/test/spec/lib/NS1/TestComponent5.def +4 -0
  32. data/test/spec/lib/NS1/TestComponent8.def +4 -0
  33. data/test/spec/lib/NS1/TestComponent9.def +4 -0
  34. data/test/spec/lib/NS2/TestComponent6.def +4 -0
  35. data/test/spec/lib/TestComponent1.def +4 -0
  36. data/test/spec/lib/TestComponent3.def +4 -0
  37. data/test/spec/test_lib_dir1/File1.def +0 -0
  38. data/test/spec/test_lib_dir1/File3.def +0 -0
  39. data/test/spec/test_lib_dir1/NS1/File4.def +0 -0
  40. data/test/spec/test_lib_dir1/NS1/NS2/File5.def +0 -0
  41. data/test/spec/test_lib_dir2/File1.def +0 -0
  42. data/test/spec/test_lib_dir2/File2.def +0 -0
  43. metadata +113 -0
@@ -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
+
@@ -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
+