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