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
data/README
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
Welcome to Proteus
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
Proteus is an abstraction of general document definition and display markup that
|
9
|
+
allows you to create and reuse complex patterns of structured content.
|
10
|
+
|
11
|
+
The purpose of Proteus is to allow you to describe documents in terms of their
|
12
|
+
content, abstracting away from the often cumbersome markup or syntax of its
|
13
|
+
native form (for example in HTML).
|
14
|
+
|
15
|
+
|
16
|
+
Project Goals:
|
17
|
+
|
18
|
+
1. Content-orientation: we should be describing content, not the structure
|
19
|
+
used to display it.
|
20
|
+
2. Human-readability: it should be easy for a human to write and maintain
|
21
|
+
documents.
|
22
|
+
3. Flexibility: it should be easy to adapt the solution to solve a wide
|
23
|
+
variety of problems.
|
24
|
+
4. Extensibility: it should be easy to change the behaviour of the system as
|
25
|
+
it is required.
|
26
|
+
|
27
|
+
|
28
|
+
For Users:
|
29
|
+
|
30
|
+
Proteus works by interpreting document definitions in YAML, for example:
|
31
|
+
|
32
|
+
Form:
|
33
|
+
- Control:
|
34
|
+
name: name
|
35
|
+
- Control:
|
36
|
+
name: age
|
37
|
+
- Control:
|
38
|
+
name: gender
|
39
|
+
type: select
|
40
|
+
options:
|
41
|
+
- male
|
42
|
+
- female
|
43
|
+
|
44
|
+
Each camelcase node indicates a "component" - a piece of content which displays
|
45
|
+
in a unique way. In the above example, the "Form" and "Control" nodes are
|
46
|
+
components and the rest of the information describes those components.
|
47
|
+
|
48
|
+
|
49
|
+
For Developers:
|
50
|
+
|
51
|
+
Proteus provides a simple system for describing new component types that
|
52
|
+
permits inheritance and composition of existing types, again in human readable
|
53
|
+
syntax. This allows users to create custom languages from existing components
|
54
|
+
quickly and easily.
|
55
|
+
|
56
|
+
|
57
|
+
The Name:
|
58
|
+
|
59
|
+
In Greek mythology, Proteus is an early sea-god who can foretell the future
|
60
|
+
and change his shape. From this feature of Proteus comes the adjective protean,
|
61
|
+
with the general meaning of "versatile", "mutable", "capable of assuming many
|
62
|
+
forms". -- Wikipedia
|
63
|
+
|
64
|
+
|
65
|
+
Homepage:
|
66
|
+
|
67
|
+
More information is available on the Proteus website,
|
68
|
+
|
69
|
+
proteus.rubyforge.org
|
70
|
+
|
71
|
+
or on Github,
|
72
|
+
|
73
|
+
github.com/wmadden/proteus
|
74
|
+
|
75
|
+
|
76
|
+
Licensing:
|
77
|
+
Proteus is free software: you can redistribute it and/or modify it under the
|
78
|
+
terms of the GNU General Public License as published by the Free Software
|
79
|
+
Foundation, either version 3 of the License, or (at your option) any later
|
80
|
+
version.
|
81
|
+
|
82
|
+
Proteus is distributed in the hope that it will be useful, but WITHOUT ANY
|
83
|
+
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
84
|
+
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
85
|
+
|
86
|
+
You should have received a copy of the GNU General Public License along with
|
87
|
+
Proteus. If not, see <http://www.gnu.org/licenses/>.
|
88
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'cucumber/rake/task'
|
4
|
+
|
5
|
+
require 'rake'
|
6
|
+
require 'spec/rake/spectask'
|
7
|
+
|
8
|
+
desc "Run all examples with RCov"
|
9
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
10
|
+
t.spec_files = FileList['test/spec/**/*.rb']
|
11
|
+
t.rcov = true
|
12
|
+
t.rcov_opts = ['--exclude', 'spec']
|
13
|
+
t.rcov_dir = 'coverage/spec/'
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'spec/rake/verify_rcov'
|
17
|
+
|
18
|
+
RCov::VerifyTask.new(:verify_rcov => :spec) do |t|
|
19
|
+
t.threshold = 100.0
|
20
|
+
t.index_html = 'coverage/spec/verify/index.html'
|
21
|
+
end
|
22
|
+
|
23
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
24
|
+
t.cucumber_opts = "--format pretty"
|
25
|
+
t.rcov = true
|
26
|
+
t.rcov_opts << %[-o "test/features/cucumber"]
|
27
|
+
end
|
28
|
+
|
29
|
+
task :doc do |t|
|
30
|
+
`rdoc -aUd src/ -o doc/api`
|
31
|
+
end
|
32
|
+
|
33
|
+
task :default => [:spec, :features, :verify_rcov]
|
data/bin/pro
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
################################################################################
|
3
|
+
# proteus
|
4
|
+
#
|
5
|
+
# Executable interface to the system.
|
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 'getoptlong'
|
25
|
+
require 'rdoc/usage'
|
26
|
+
|
27
|
+
require 'Facade.rb'
|
28
|
+
require 'TemplateRenderer.rb'
|
29
|
+
require 'exceptions.rb'
|
30
|
+
|
31
|
+
include Proteus
|
32
|
+
|
33
|
+
PROTEUS_VERSION = "v0.9.0"
|
34
|
+
|
35
|
+
USAGE =
|
36
|
+
"""
|
37
|
+
Usage:
|
38
|
+
proteus [--path PATH] FILE
|
39
|
+
proteus --inline COMPONENT [--props PROPERTIES] [CHILDREN]
|
40
|
+
proteus --help
|
41
|
+
|
42
|
+
Options:
|
43
|
+
--help, -h Display this message.
|
44
|
+
|
45
|
+
--inline, -i Parse inline. Takes component information on the
|
46
|
+
command line and outputs the rendered component
|
47
|
+
instance.
|
48
|
+
|
49
|
+
--path, -p Sets the path to search for component definitions.
|
50
|
+
Defaults to /usr/lib/proteus.
|
51
|
+
|
52
|
+
--props, -P Sets the properties for an inline component.
|
53
|
+
|
54
|
+
--no-current, -C Don't add current directory to path.
|
55
|
+
|
56
|
+
--version, -V Output version.
|
57
|
+
|
58
|
+
"""
|
59
|
+
|
60
|
+
PROTEUS_PATH = 'PROTEUS_PATH'
|
61
|
+
|
62
|
+
def exit_error( error )
|
63
|
+
puts error
|
64
|
+
puts USAGE
|
65
|
+
exit( 1 )
|
66
|
+
end
|
67
|
+
|
68
|
+
def parse_props( props )
|
69
|
+
result = {}
|
70
|
+
|
71
|
+
props.split( ',' ).each do |prop|
|
72
|
+
pair = prop.split(':')
|
73
|
+
result[ pair[0] ] = pair[1]
|
74
|
+
end
|
75
|
+
|
76
|
+
return result
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def parse_command_line
|
81
|
+
|
82
|
+
@opts.each do |opt, arg|
|
83
|
+
case opt
|
84
|
+
when '--help', '-h'
|
85
|
+
puts( USAGE )
|
86
|
+
exit( 0 )
|
87
|
+
when '--inline', '-i'
|
88
|
+
@inline = true
|
89
|
+
when '--props', '-P'
|
90
|
+
@props = parse_props( arg )
|
91
|
+
when '--path', '-p'
|
92
|
+
@path = arg
|
93
|
+
when '--namespace', '-n'
|
94
|
+
@current_ns = arg
|
95
|
+
when '--no-current', '-C'
|
96
|
+
@exclude_current = true
|
97
|
+
when '--version', '-V'
|
98
|
+
puts( PROTEUS_VERSION )
|
99
|
+
exit( 0 )
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
#------------------------------
|
106
|
+
# ENTRY POINT
|
107
|
+
#------------------------------
|
108
|
+
|
109
|
+
# Option variables
|
110
|
+
@inline = false
|
111
|
+
@path = ENV[ PROTEUS_PATH ] || FileHelper::DEFAULT_PATH
|
112
|
+
@props = {}
|
113
|
+
@current_ns = []
|
114
|
+
@exclude_current = false
|
115
|
+
|
116
|
+
# Valid options
|
117
|
+
@opts = GetoptLong.new(
|
118
|
+
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
119
|
+
[ '--path', '-p', GetoptLong::REQUIRED_ARGUMENT ],
|
120
|
+
[ '--inline', '-i', GetoptLong::NO_ARGUMENT ],
|
121
|
+
[ '--props', '-P', GetoptLong::REQUIRED_ARGUMENT ],
|
122
|
+
[ '--namespace', '-n', GetoptLong::REQUIRED_ARGUMENT ],
|
123
|
+
[ '--no-current', '-C', GetoptLong::NO_ARGUMENT ],
|
124
|
+
[ '--version', '-V', GetoptLong::NO_ARGUMENT ]
|
125
|
+
)
|
126
|
+
|
127
|
+
# Parse command line
|
128
|
+
parse_command_line
|
129
|
+
|
130
|
+
# Set up system
|
131
|
+
facade = Facade.new
|
132
|
+
|
133
|
+
facade.path = @path + ':.'
|
134
|
+
|
135
|
+
# Initialize renderer
|
136
|
+
renderer = TemplateRenderer.new
|
137
|
+
|
138
|
+
# Parse input
|
139
|
+
if not @inline
|
140
|
+
|
141
|
+
# from file
|
142
|
+
|
143
|
+
if ARGV.length < 1
|
144
|
+
exit_error( "Error: no target given." )
|
145
|
+
elsif ARGV.length > 1
|
146
|
+
exit_error( "Error: multiple targets given." )
|
147
|
+
end
|
148
|
+
|
149
|
+
file = ARGV[0]
|
150
|
+
|
151
|
+
tree = facade.parse_file( file, @current_ns )
|
152
|
+
|
153
|
+
puts renderer.render( tree )
|
154
|
+
|
155
|
+
else
|
156
|
+
|
157
|
+
# from command line
|
158
|
+
|
159
|
+
if ARGV.length < 1
|
160
|
+
exit_error( "Error: no component identifier given." )
|
161
|
+
end
|
162
|
+
|
163
|
+
component_id = ARGV[0]
|
164
|
+
|
165
|
+
ARGV.shift
|
166
|
+
component_children = ARGV
|
167
|
+
|
168
|
+
component_properties = @props
|
169
|
+
|
170
|
+
class_path = facade.input_parser.parse_component_id( component_id )
|
171
|
+
|
172
|
+
begin
|
173
|
+
component_class = facade.definition_helper.get_class( class_path,
|
174
|
+
@current_ns )
|
175
|
+
rescue Exceptions::DefinitionUnavailable
|
176
|
+
exit_error( "Error: no definition found for '" + component_id + "'." )
|
177
|
+
end
|
178
|
+
|
179
|
+
component_children = facade.input_parser.parse_yaml( component_children,
|
180
|
+
@current_ns )
|
181
|
+
|
182
|
+
instance = ComponentInstance.new( component_class, component_properties,
|
183
|
+
component_children )
|
184
|
+
|
185
|
+
facade.input_parser.parse_instance( instance, @current_ns )
|
186
|
+
|
187
|
+
puts renderer.render( instance )
|
188
|
+
|
189
|
+
end
|
data/lib/ClassParser.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
################################################################################
|
2
|
+
# ClassParser.rb
|
3
|
+
#
|
4
|
+
# Responsible for interpreting YAML for component 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 File.expand_path( File.join(File.dirname(__FILE__), 'exceptions.rb') )
|
24
|
+
require File.expand_path( File.join(File.dirname(__FILE__), 'ComponentClass.rb') )
|
25
|
+
|
26
|
+
|
27
|
+
module Proteus
|
28
|
+
|
29
|
+
#
|
30
|
+
# Provides functions for parsing component definitions (for component
|
31
|
+
# classes).
|
32
|
+
#
|
33
|
+
class ClassParser
|
34
|
+
|
35
|
+
# The regex for valid class names
|
36
|
+
@@CLASS_RE = /^([A-Z][a-zA-Z_0-9]*)(?:[\s]*<[\s]*([A-Z][a-zA-Z_0-9]*))?$/
|
37
|
+
@@CHILDREN = "children"
|
38
|
+
|
39
|
+
#---------------------------------------------------------------------------
|
40
|
+
#
|
41
|
+
# Methods
|
42
|
+
#
|
43
|
+
#---------------------------------------------------------------------------
|
44
|
+
|
45
|
+
public
|
46
|
+
|
47
|
+
#
|
48
|
+
# Parses YAML and returns the resultant component class.
|
49
|
+
#
|
50
|
+
# yaml: the YAML to parse
|
51
|
+
# new_class: the class instance to parse
|
52
|
+
#
|
53
|
+
def parse_yaml( yaml, new_class = nil )
|
54
|
+
result = new_class || ComponentClass.new
|
55
|
+
|
56
|
+
# Must be a hash of length one containing a hash
|
57
|
+
if not ( yaml.is_a?(Hash) and yaml.length == 1 and
|
58
|
+
(yaml.values[0].nil? or yaml.values[0].is_a?(Hash)) ) then
|
59
|
+
|
60
|
+
raise Exceptions::DefinitionMalformed, "Class definition malformed"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Parse the class name
|
64
|
+
name = yaml.keys[0]
|
65
|
+
match = @@CLASS_RE.match( name )
|
66
|
+
|
67
|
+
# If there's no match, the definition is malformed
|
68
|
+
if match.nil?
|
69
|
+
raise Exceptions::DefinitionMalformed,
|
70
|
+
"Class identifier '" + name + "' malformed."
|
71
|
+
end
|
72
|
+
|
73
|
+
# Set properties of class
|
74
|
+
result.name = match[1]
|
75
|
+
result.parent = match[2]
|
76
|
+
result.properties = yaml.values[0] || {}
|
77
|
+
result.children = result.properties.delete(@@CHILDREN) || []
|
78
|
+
|
79
|
+
return result
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
################################################################################
|
2
|
+
# ComponentClass.rb
|
3
|
+
#
|
4
|
+
# Represents an class of 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
|
+
module Proteus
|
24
|
+
|
25
|
+
class ComponentClass
|
26
|
+
|
27
|
+
DEFAULT_CLASS = ComponentClass.new()
|
28
|
+
|
29
|
+
#---------------------------------------------------------------------------
|
30
|
+
#
|
31
|
+
# Constructor
|
32
|
+
#
|
33
|
+
#---------------------------------------------------------------------------
|
34
|
+
|
35
|
+
def initialize( )
|
36
|
+
@properties = {}
|
37
|
+
@children = []
|
38
|
+
end
|
39
|
+
|
40
|
+
#---------------------------------------------------------------------------
|
41
|
+
#
|
42
|
+
# Properties
|
43
|
+
#
|
44
|
+
#---------------------------------------------------------------------------
|
45
|
+
|
46
|
+
attr_accessor :name, :namespace, :parent, :properties, :children
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|