proteus 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -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
|
data/lib/Facade.rb
ADDED
@@ -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
|
+
|