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