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,76 @@
1
+ ################################################################################
2
+ # ComponentInstance.rb
3
+ #
4
+ # Represents an instance of a component.
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__), 'ComponentClass.rb') )
24
+
25
+
26
+ module Proteus
27
+
28
+ class ComponentInstance
29
+
30
+ #---------------------------------------------------------------------------
31
+ #
32
+ # Constructor
33
+ #
34
+ #---------------------------------------------------------------------------
35
+
36
+ def initialize( kind = ComponentClass::DEFAULT_CLASS,
37
+ properties = {}, children = [] )
38
+
39
+ @kind = kind
40
+ @properties = properties
41
+ @children = children
42
+
43
+ end
44
+
45
+ #---------------------------------------------------------------------------
46
+ #
47
+ # Properties
48
+ #
49
+ #---------------------------------------------------------------------------
50
+
51
+ attr_accessor :kind, :children, :properties
52
+
53
+ #---------------------------------------------------------------------------
54
+ #
55
+ # Methods
56
+ #
57
+ #---------------------------------------------------------------------------
58
+
59
+ #
60
+ # Merges the component's properties with the class's and returns the result.
61
+ #
62
+ def final_properties
63
+ return kind.properties.merge( @properties )
64
+ end
65
+
66
+ #
67
+ # Merges the component's children with the class's and returns the result.
68
+ #
69
+ def final_children
70
+ return kind.children.merge( @children )
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+
@@ -0,0 +1,157 @@
1
+ ################################################################################
2
+ # DefinitionHelper.rb
3
+ #
4
+ # Responsible for loading definitions and maintaining the set of loaded classes.
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 'yaml'
24
+
25
+ require File.expand_path( File.join(File.dirname(__FILE__), 'DefinitionParser.rb') )
26
+ require File.expand_path( File.join(File.dirname(__FILE__), 'FileHelper.rb') )
27
+ require File.expand_path( File.join(File.dirname(__FILE__), 'exceptions.rb') )
28
+
29
+
30
+ module Proteus
31
+
32
+ class DefinitionHelper
33
+
34
+ #---------------------------------------------------------------------------
35
+ #
36
+ # Constructor
37
+ #
38
+ #---------------------------------------------------------------------------
39
+
40
+ def initialize( definition_parser = nil, path = nil )
41
+ @path = path
42
+ @definition_parser = definition_parser
43
+
44
+ @loaded_classes = {}
45
+ @loading = []
46
+ end
47
+
48
+ #---------------------------------------------------------------------------
49
+ #
50
+ # Properties
51
+ #
52
+ #---------------------------------------------------------------------------
53
+
54
+ public
55
+
56
+ attr_accessor :path, :definition_parser
57
+
58
+ private
59
+
60
+ attr_accessor :loaded_classes
61
+
62
+ #---------------------------------------------------------------------------
63
+ #
64
+ # Methods
65
+ #
66
+ #---------------------------------------------------------------------------
67
+
68
+ public
69
+
70
+ #
71
+ # Returns the given class.
72
+ #
73
+ # class_path: an array containing the namespaces and class id of the class
74
+ # current_ns: the current namespace, an array of namespace identifiers
75
+ #
76
+ def get_class( class_path, current_ns )
77
+
78
+ current_ns = current_ns || []
79
+
80
+ # 1. Search the current namespace
81
+ # 2. Search the default namespace
82
+ begin
83
+ result = find_class( current_ns.concat(class_path) )
84
+ rescue Exceptions::DefinitionUnavailable
85
+ result = find_class( class_path )
86
+ end
87
+
88
+ end
89
+
90
+
91
+ private
92
+
93
+ #
94
+ # Searches for the given class and loads it if not found.
95
+ #
96
+ # class_path: the fully qualified class path, including ALL namespaces.
97
+ #
98
+ def find_class( class_path )
99
+
100
+ # If it's already loaded, return it.
101
+ if @loaded_classes.has_key?( class_path )
102
+ return @loaded_classes[ class_path ]
103
+ end
104
+
105
+ # Otherwise create it,
106
+ new_class = ComponentClass.new
107
+
108
+ # add it to the dictionary,
109
+ @loaded_classes[ class_path ] = new_class
110
+
111
+ # load its definition,
112
+ begin
113
+ new_class = load_class( class_path, new_class )
114
+ rescue Exception => exception
115
+ # Load failed so delete it from the dictionary
116
+ # TODO: consider dropping entire dictionary, since linked classes might
117
+ # also be affected
118
+ @loaded_classes.delete( class_path )
119
+
120
+ raise exception
121
+ end
122
+
123
+ # and return it.
124
+ return new_class
125
+
126
+ end
127
+
128
+ #
129
+ # Loads the given class.
130
+ #
131
+ # class_path: the full path of the class, including all namespaces
132
+ #
133
+ def load_class( class_path, new_class )
134
+
135
+ file = FileHelper.find_definition( class_path, @path )
136
+
137
+ if file.nil?
138
+ raise Exceptions::DefinitionUnavailable,
139
+ "File not found for class path: '" + class_path.inspect + "'"
140
+ end
141
+
142
+ yaml = YAML.load_file( file )
143
+
144
+ @definition_parser.parse_yaml( yaml, new_class, class_path.slice(0..-2) )
145
+
146
+ if new_class.name != class_path[ class_path.length - 1 ]
147
+ raise Exceptions::DefinitionMalformed,
148
+ "Definition class name ('" + new_class.name +
149
+ "') does not match file name ('" +
150
+ class_path[ class_path.length - 1 ] + "')."
151
+ end
152
+
153
+ return new_class
154
+ end
155
+
156
+ end
157
+ end
@@ -0,0 +1,107 @@
1
+ ################################################################################
2
+ # DefinitionParser.rb
3
+ #
4
+ # Responsible for interpreting YAML for definition 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
+ require File.expand_path( File.join(File.dirname(__FILE__), 'ComponentClass.rb') )
24
+
25
+
26
+ module Proteus
27
+
28
+ class DefinitionParser
29
+
30
+ #---------------------------------------------------------------------------
31
+ #
32
+ # Constructor
33
+ #
34
+ #---------------------------------------------------------------------------
35
+
36
+ def initialize( definition_helper = nil, class_parser = nil,
37
+ input_parser = nil )
38
+
39
+ @definition_helper = definition_helper
40
+ @class_parser = class_parser
41
+ @input_parser = input_parser
42
+
43
+ end
44
+
45
+ #---------------------------------------------------------------------------
46
+ #
47
+ # Properties
48
+ #
49
+ #---------------------------------------------------------------------------
50
+
51
+ public
52
+
53
+ attr_accessor :definition_helper, :class_parser, :input_parser
54
+
55
+ #---------------------------------------------------------------------------
56
+ #
57
+ # Methods
58
+ #
59
+ #---------------------------------------------------------------------------
60
+
61
+ public
62
+
63
+ #------------------------------
64
+ # parse_yaml
65
+ #------------------------------
66
+
67
+ #
68
+ # Takes the YAML input read directly from the definition file and parses it,
69
+ # returning the loaded ComponentClass.
70
+ #
71
+ # yaml: The input YAML to be parsed.
72
+ # component_class: The component class to load.
73
+ #
74
+ def parse_yaml( yaml, component_class, current_ns = nil )
75
+
76
+ result = component_class || ComponentClass.new
77
+
78
+ # Let the class parser handle interpreting the YAML, then load the parent
79
+ # class and parse all the values in the children and properties of the new
80
+ # component class.
81
+
82
+ @class_parser.parse_yaml( yaml, result )
83
+
84
+ # Get the parent class
85
+ if result.parent != nil
86
+ result.parent = @definition_helper.get_class( result.parent.split(':'),
87
+ current_ns )
88
+ end
89
+
90
+ # Parse properties
91
+ for property in result.properties
92
+ result.properties[ property[0] ] =
93
+ @input_parser.parse_yaml( property[1], current_ns )
94
+ end
95
+
96
+ # Parse children
97
+ result.children.length.times do |i|
98
+ result.children[i] = @input_parser.parse_yaml( result.children[i],
99
+ current_ns )
100
+ end
101
+
102
+ return result
103
+ end
104
+
105
+ end
106
+
107
+ end
@@ -0,0 +1,116 @@
1
+ ################################################################################
2
+ # Facade.rb
3
+ #
4
+ # An implementation of the Facade pattern. Provides an easy way to handle the
5
+ # parser and helper classes.
6
+ # -----------------------------------------------------------------------------
7
+ # (C) Copyright 2009 William Madden
8
+ #
9
+ # This file is part of Proteus.
10
+ #
11
+ # Proteus is free software: you can redistribute it and/or modify it under the
12
+ # terms of the GNU General Public License as published by the Free Software
13
+ # Foundation, either version 3 of the License, or (at your option) any later
14
+ # version.
15
+ #
16
+ # Proteus is distributed in the hope that it will be useful, but WITHOUT ANY
17
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the GNU General Public License along with
21
+ # Proteus. If not, see <http://www.gnu.org/licenses/>.
22
+ ################################################################################
23
+
24
+ require File.expand_path( File.join(File.dirname(__FILE__), 'DefinitionHelper.rb') )
25
+
26
+ require File.expand_path( File.join(File.dirname(__FILE__), 'InstanceParser.rb') )
27
+ require File.expand_path( File.join(File.dirname(__FILE__), 'ClassParser.rb') )
28
+ require File.expand_path( File.join(File.dirname(__FILE__), 'InputParser.rb') )
29
+ require File.expand_path( File.join(File.dirname(__FILE__), 'DefinitionParser.rb') )
30
+
31
+ module Proteus
32
+
33
+ class Facade
34
+
35
+ #---------------------------------------------------------------------------
36
+ #
37
+ # Constructor
38
+ #
39
+ #---------------------------------------------------------------------------
40
+
41
+ def initialize( )
42
+
43
+ # Instance parser
44
+ @instance_parser = InstanceParser.new
45
+
46
+ # Class parser
47
+ @class_parser = ClassParser.new
48
+
49
+ # Definition parser
50
+ @definition_parser = DefinitionParser.new
51
+ @definition_parser.class_parser = @class_parser
52
+
53
+ # Definition helper
54
+ @definition_helper = DefinitionHelper.new
55
+ @definition_helper.definition_parser = @definition_parser
56
+
57
+ @definition_parser.definition_helper = @definition_helper
58
+
59
+ # Input parser
60
+ @input_parser = InputParser.new
61
+ @input_parser.instance_parser = @instance_parser
62
+ @input_parser.definition_helper = @definition_helper
63
+
64
+ @definition_parser.input_parser = @input_parser
65
+
66
+ end
67
+
68
+ #---------------------------------------------------------------------------
69
+ #
70
+ # Properties
71
+ #
72
+ #---------------------------------------------------------------------------
73
+
74
+ public
75
+
76
+ # Parsers
77
+ attr_accessor :class_parser, :instance_parser, :definition_parser,
78
+ :input_parser
79
+
80
+ # Helpers
81
+ attr_accessor :definition_helper
82
+
83
+ # Properties
84
+ attr_reader :path
85
+
86
+ def path=( value )
87
+ @path = value
88
+ @definition_helper.path = value
89
+ end
90
+
91
+ #---------------------------------------------------------------------------
92
+ #
93
+ # Methods
94
+ #
95
+ #---------------------------------------------------------------------------
96
+
97
+ public
98
+
99
+ #
100
+ # Parses the given input YAML.
101
+ #
102
+ def parse_input( yaml, current_ns = [] )
103
+ return @input_parser.parse_yaml( yaml )
104
+ end
105
+
106
+ #
107
+ # Parses the given input file.
108
+ #
109
+ def parse_file( file, current_ns = [] )
110
+ return @input_parser.parse_yaml( YAML.load_file(file) )
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+