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.
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
+