reality-generators 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,152 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module Reality #nodoc
16
+ module Generators #nodoc
17
+
18
+ # Error raised when template unable to generate
19
+ class GeneratorError < StandardError
20
+ attr_reader :cause
21
+
22
+ def initialize(message, cause = nil)
23
+ super(message)
24
+ @cause = cause
25
+ end
26
+ end
27
+
28
+ # Base class for all templates
29
+ class Template < Reality::BaseElement
30
+ attr_reader :template_set
31
+ attr_reader :template_key
32
+ attr_reader :guard
33
+ attr_reader :helpers
34
+ attr_reader :target
35
+ attr_reader :facets
36
+ attr_reader :extra_data
37
+
38
+ def initialize(template_set, facets, target, template_key, helpers, options = {})
39
+ Generators.error("Unexpected facets: #{facets.inspect}") unless facets.is_a?(Array) && facets.all? { |a| a.is_a?(Symbol) }
40
+ Generators.error("Unknown target '#{target}' for template '#{template_key}'. Valid targets include: #{template_set.container.target_manager.target_keys.join(', ')}") unless template_set.container.target_manager.is_target_valid?(target)
41
+ @template_set = template_set
42
+ @facets = facets
43
+ @target = target
44
+ @template_key = template_key
45
+ @helpers = helpers
46
+ @guard = options[:guard]
47
+ @name = options[:name] if options[:name]
48
+ @extra_data = options[:extra_data] || {}
49
+ template_set.send(:register_template, self)
50
+ end
51
+
52
+ def to_s
53
+ name
54
+ end
55
+
56
+ def applicable?(faceted_object)
57
+ return true if self.facets.empty?
58
+ return false unless faceted_object.respond_to?(:facet_enabled?)
59
+ self.facets.all? { |facet_key| faceted_object.facet_enabled?(facet_key) }
60
+ end
61
+
62
+ def output_path
63
+ Generators.error('output_path unimplemented')
64
+ end
65
+
66
+ def generate(target_basedir, element, unprocessed_files)
67
+ Generators.debug("Generating #{self.name} for #{self.target} #{name_for_element(element)}")
68
+ return nil unless guard_allows?(element)
69
+
70
+ generate!(target_basedir, element, unprocessed_files)
71
+ end
72
+
73
+ def name
74
+ @name ||= "#{self.template_set.name}:#{self.template_key.gsub(/.*\/templates\/(.*)\.#{template_extension}$/, '\1')}"
75
+ end
76
+
77
+ protected
78
+
79
+ def guard_allows?(element)
80
+ return true if self.guard.nil?
81
+ render_context = create_context(element)
82
+ context_binding = render_context.context_binding
83
+ eval(self.guard, context_binding, "#{self.template_key}#Guard")
84
+ end
85
+
86
+ def template_extension
87
+ ''
88
+ end
89
+
90
+ def generate!(target_basedir, element, unprocessed_files)
91
+ Generators.error('generate not implemented')
92
+ end
93
+
94
+ def name_for_element(element)
95
+ element.respond_to?(:qualified_name) ? element.qualified_name : element.name
96
+ end
97
+
98
+ def create_context(value)
99
+ context = RenderContext.new
100
+ context.set_local_variable(self.target.to_s.gsub(/^.*\./, ''), value)
101
+ self.extra_data.each_pair do |k, v|
102
+ context.set_local_variable(k, v)
103
+ end
104
+ self.helpers.each do |helper|
105
+ context.add_helper(helper)
106
+ end
107
+ context
108
+ end
109
+ end
110
+
111
+ # Base class for templates that generate a single file
112
+ class SingleFileOutputTemplate < Template
113
+ attr_reader :output_filename_pattern
114
+
115
+ def initialize(template_set, facets, target, template_key, output_filename_pattern, helpers, options = {})
116
+ super(template_set, facets, target, template_key, helpers, options)
117
+ @output_filename_pattern = output_filename_pattern
118
+ end
119
+
120
+ def output_path
121
+ output_filename_pattern
122
+ end
123
+
124
+ protected
125
+
126
+ def generate!(target_basedir, element, unprocessed_files)
127
+ object_name = name_for_element(element)
128
+ render_context = create_context(element)
129
+ context_binding = render_context.context_binding
130
+ begin
131
+ output_filename = eval("\"#{self.output_filename_pattern}\"", context_binding, "#{self.template_key}#Filename")
132
+ output_filename = File.join(target_basedir, output_filename)
133
+ unprocessed_files.delete(output_filename)
134
+ result = self.render_to_string(context_binding)
135
+ FileUtils.mkdir_p File.dirname(output_filename) unless File.directory?(File.dirname(output_filename))
136
+ if File.exist?(output_filename) && IO.read(output_filename) == result
137
+ Generators.debug "Skipped generation of #{self.name} for #{self.target} #{object_name} to #{output_filename} due to no changes"
138
+ else
139
+ File.open(output_filename, 'w') { |f| f.write(result) }
140
+ Generators.debug "Generated #{self.name} for #{self.target} #{object_name} to #{output_filename}"
141
+ end
142
+ rescue => e
143
+ raise GeneratorError.new("Error generating #{self.name} for #{self.target} #{object_name} due to '#{e}'", e)
144
+ end
145
+ end
146
+
147
+ def render_to_string(context_binding)
148
+ Generators.error('render_to_string not implemented')
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,64 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module Reality #nodoc
16
+ module Generators #nodoc
17
+
18
+ # A collection of templates
19
+ class TemplateSet < Reality::BaseElement
20
+ attr_reader :name
21
+ attr_reader :container
22
+ attr_accessor :required_template_sets
23
+ attr_accessor :description
24
+
25
+ def initialize(container, name, options = {}, &block)
26
+ @container = container
27
+ @name = name
28
+ @required_template_sets = []
29
+ super(options, &block)
30
+ self.required_template_sets.each do |template_set_name|
31
+ unless container.template_set_by_name?(template_set_name)
32
+ raise "TemplateSet '#{self.name}' defined requirement on template set '#{template_set_name}' that does not exist."
33
+ end
34
+ end
35
+ container.send(:register_template_set, self)
36
+ end
37
+
38
+ def templates
39
+ template_map.values
40
+ end
41
+
42
+ def template_by_name?(name)
43
+ !!template_map[name.to_s]
44
+ end
45
+
46
+ def template_by_name(name)
47
+ template = template_map[name.to_s]
48
+ Generators.error("Unable to locate template #{name}") unless template
49
+ template
50
+ end
51
+
52
+ private
53
+
54
+ def register_template(template)
55
+ Generators.error("Template already exists with specified name #{template.name}") if template_map[template.name]
56
+ template_map[template.name] = template
57
+ end
58
+
59
+ def template_map
60
+ @templates ||= Reality::OrderedHash.new
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,65 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module Reality #nodoc
16
+ module Generators #nodoc
17
+
18
+ module TemplateSetContainer
19
+ def template_sets
20
+ template_set_map.values
21
+ end
22
+
23
+ def template_set(name, options = {}, &block)
24
+ if name.is_a?(Hash) && name.size == 1
25
+ req = name.values[0]
26
+ options = options.dup
27
+ options[:required_template_sets] = req.is_a?(Array) ? req : [req]
28
+ name = name.keys[0]
29
+ end
30
+ new_template_set(name.to_s, options, &block)
31
+ end
32
+
33
+ def template_set_by_name?(name)
34
+ !!template_set_map[name.to_s]
35
+ end
36
+
37
+ def template_set_by_name(name)
38
+ template_set = template_set_map[name.to_s]
39
+ Generators.error("Unable to locate template_set #{name}") unless template_set
40
+ template_set
41
+ end
42
+
43
+ def target_manager
44
+ @target_manager ||= Reality::Generators::TargetManager.new(self)
45
+ end
46
+
47
+ protected
48
+
49
+ def register_template_set(template_set)
50
+ raise "Attempting to redefine template_set #{template_set.name}" if template_set_map[template_set.name.to_s]
51
+ template_set_map[template_set.name.to_s] = template_set
52
+ end
53
+
54
+ def new_template_set(name, options, &block)
55
+ Generators.error('new_template_set not implemented')
56
+ end
57
+
58
+ private
59
+
60
+ def template_set_map
61
+ @template_sets ||= Reality::OrderedHash.new
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,28 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ require 'erb'
16
+
17
+ require 'reality/core'
18
+ require 'reality/naming'
19
+ require 'reality/orderedhash'
20
+
21
+ require 'reality/generators/core'
22
+ require 'reality/generators/render_context'
23
+ require 'reality/generators/target_manager'
24
+ require 'reality/generators/template'
25
+ require 'reality/generators/ruby_template'
26
+ require 'reality/generators/erb_template'
27
+ require 'reality/generators/template_set'
28
+ require 'reality/generators/template_set_container'
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{reality-generators}
5
+ s.version = '1.0.0'
6
+ s.platform = Gem::Platform::RUBY
7
+
8
+ s.authors = ['Peter Donald']
9
+ s.email = %q{peter@realityforge.org}
10
+
11
+ s.homepage = %q{https://github.com/realityforge/reality-generators}
12
+ s.summary = %q{A basic toolkit for abstracting the generation of files from model objects.}
13
+ s.description = %q{A basic toolkit for abstracting the generation of files from model objects.}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
18
+ s.default_executable = []
19
+ s.require_paths = %w(lib)
20
+
21
+ s.has_rdoc = false
22
+ s.rdoc_options = %w(--line-numbers --inline-source --title reality-generators)
23
+
24
+ s.add_dependency 'reality-core', '= 1.4.0'
25
+ s.add_dependency 'reality-naming', '= 1.4.0'
26
+ s.add_dependency 'reality-orderedhash', '= 1.0.0'
27
+
28
+ s.add_development_dependency(%q<minitest>, ['= 5.9.1'])
29
+ s.add_development_dependency(%q<test-unit>, ['= 3.1.5'])
30
+ end
@@ -0,0 +1,6 @@
1
+ /* DO NOT EDIT: File is auto-generated */
2
+
3
+ @javax.annotation.Generated( "reality-generators" )
4
+ public class <%= component.name %>
5
+ {
6
+ }
@@ -0,0 +1,3 @@
1
+ def generate(model)
2
+ "Here is a #{model.name}"
3
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path('../../helper', __FILE__)
2
+
3
+ class Reality::Generators::TestErbTemplate < Reality::TestCase
4
+
5
+ class SimpleModel
6
+ def name
7
+ 'SimpleModel'
8
+ end
9
+
10
+ def facet_enabled?(facet)
11
+ true
12
+ end
13
+ end
14
+
15
+ def test_erb_template
16
+ template_set = Reality::Generators::TemplateSet.new(TestTemplateSetContainer, 'foo')
17
+
18
+ output_filename_pattern = 'main/java/#{component.name}.java'
19
+ template_filename = File.expand_path(File.dirname(__FILE__) + '/templates/mytemplate.java.erb')
20
+ TestTemplateSetContainer.target_manager.target(:component)
21
+
22
+ template1 = Reality::Generators::ErbTemplate.new(template_set, [], :component, template_filename, output_filename_pattern, [], {})
23
+
24
+ assert_equal output_filename_pattern, template1.output_filename_pattern
25
+ assert_equal output_filename_pattern, template1.output_path
26
+ assert_equal template_set, template1.template_set
27
+ assert_equal [], template1.facets
28
+ assert_equal :component, template1.target
29
+ assert_equal [], template1.helpers
30
+ assert_equal template_filename, template1.template_key
31
+ assert_equal nil, template1.guard
32
+ assert_equal({}, template1.extra_data)
33
+ assert_equal 'foo:mytemplate.java', template1.name
34
+
35
+ target_basedir = "#{temp_dir}/generated/erb_template"
36
+ target_filename = "#{target_basedir}/main/java/SimpleModel.java"
37
+ other_filename = "#{target_basedir}/main/java/Other.java"
38
+ unprocessed_files = %W(#{target_filename} #{other_filename})
39
+ assert_equal false, File.exist?(target_filename)
40
+ template1.generate(target_basedir, SimpleModel.new, unprocessed_files)
41
+ assert_equal true, File.exist?(target_filename)
42
+ assert_equal 1, unprocessed_files.size
43
+
44
+ assert_equal <<JAVA, IO.read(target_filename)
45
+ /* DO NOT EDIT: File is auto-generated */
46
+
47
+ @javax.annotation.Generated( "reality-generators" )
48
+ public class SimpleModel
49
+ {
50
+ }
51
+ JAVA
52
+ end
53
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path('../../helper', __FILE__)
2
+
3
+ class Reality::Generators::TestRenderContext < Reality::TestCase
4
+
5
+ module MyHelper
6
+ def gen_x
7
+ 'X'
8
+ end
9
+
10
+ def gen_y
11
+ 'Y'
12
+ end
13
+ end
14
+
15
+ def test_basic_operation
16
+ render_context = Reality::Generators::RenderContext.new
17
+
18
+ assert_equal 'Missing', eval("gen_x rescue 'Missing'", render_context.context_binding)
19
+ assert_equal 'Missing', eval("gen_y rescue 'Missing'", render_context.context_binding)
20
+ assert_equal 'Missing', eval("a rescue 'Missing'", render_context.context_binding)
21
+ assert_equal 'Missing', eval("b rescue 'Missing'", render_context.context_binding)
22
+
23
+ render_context.add_helper(MyHelper)
24
+
25
+ assert_equal 'X', eval("gen_x rescue 'Missing'", render_context.context_binding)
26
+ assert_equal 'Y', eval("gen_y rescue 'Missing'", render_context.context_binding)
27
+ assert_equal 'Missing', eval("a rescue 'Missing'", render_context.context_binding)
28
+ assert_equal 'Missing', eval("b rescue 'Missing'", render_context.context_binding)
29
+
30
+ render_context.set_local_variable(:a, 'A')
31
+
32
+ assert_equal 'X', eval("gen_x rescue 'Missing'", render_context.context_binding)
33
+ assert_equal 'Y', eval("gen_y rescue 'Missing'", render_context.context_binding)
34
+ assert_equal 'A', eval("a rescue 'Missing'", render_context.context_binding)
35
+ assert_equal 'Missing', eval("b rescue 'Missing'", render_context.context_binding)
36
+
37
+ render_context.set_local_variable(:b, 'B')
38
+
39
+ assert_equal 'X', eval("gen_x rescue 'Missing'", render_context.context_binding)
40
+ assert_equal 'Y', eval("gen_y rescue 'Missing'", render_context.context_binding)
41
+ assert_equal 'A', eval("a rescue 'Missing'", render_context.context_binding)
42
+ assert_equal 'B', eval("b rescue 'Missing'", render_context.context_binding)
43
+ end
44
+ end
@@ -0,0 +1,46 @@
1
+ require File.expand_path('../../helper', __FILE__)
2
+
3
+ class Reality::Generators::TestRubyTemplate < Reality::TestCase
4
+
5
+ class SimpleModel
6
+ def name
7
+ 'SimpleModel'
8
+ end
9
+
10
+ def facet_enabled?(facet)
11
+ true
12
+ end
13
+ end
14
+
15
+ def test_ruby_template
16
+ template_set = Reality::Generators::TemplateSet.new(TestTemplateSetContainer, 'foo')
17
+
18
+ output_filename_pattern = 'main/java/#{component.name}.java'
19
+ template_filename = File.expand_path(File.dirname(__FILE__) + '/templates/rubytemplate.rb')
20
+ TestTemplateSetContainer.target_manager.target(:component)
21
+
22
+ template1 = Reality::Generators::RubyTemplate.new(template_set, [], :component, template_filename, output_filename_pattern, [], {})
23
+
24
+ assert_equal output_filename_pattern, template1.output_filename_pattern
25
+ assert_equal output_filename_pattern, template1.output_path
26
+ assert_equal template_set, template1.template_set
27
+ assert_equal [], template1.facets
28
+ assert_equal :component, template1.target
29
+ assert_equal [], template1.helpers
30
+ assert_equal template_filename, template1.template_key
31
+ assert_equal nil, template1.guard
32
+ assert_equal({}, template1.extra_data)
33
+ assert_equal 'foo:rubytemplate', template1.name
34
+
35
+ target_basedir = "#{temp_dir}/generated/ruby_template"
36
+ target_filename = "#{target_basedir}/main/java/SimpleModel.java"
37
+ other_filename = "#{target_basedir}/main/java/Other.java"
38
+ unprocessed_files = %W(#{target_filename} #{other_filename})
39
+ assert_equal false, File.exist?(target_filename)
40
+ template1.generate(target_basedir, SimpleModel.new, unprocessed_files)
41
+ assert_equal true, File.exist?(target_filename)
42
+ assert_equal 1, unprocessed_files.size
43
+
44
+ assert_equal 'Here is a SimpleModel', IO.read(target_filename)
45
+ end
46
+ end
@@ -0,0 +1,89 @@
1
+ require File.expand_path('../../helper', __FILE__)
2
+
3
+ class Reality::Generators::TestTargetManager < Reality::TestCase
4
+
5
+ def test_target
6
+ target_manager = Reality::Generators::TargetManager.new(TestTemplateSetContainer)
7
+ target1 = Reality::Generators::Target.new(target_manager, :repository, nil, {})
8
+
9
+ assert_equal :repository, target1.qualified_key
10
+ assert_equal :repository, target1.key
11
+ assert_equal nil, target1.container_key
12
+ assert_equal 'repositories', target1.access_method
13
+ assert_equal nil, target1.facet_key
14
+ assert_equal true, target1.standard?
15
+
16
+ target2 = Reality::Generators::Target.new(target_manager, :data_module, :repository, {})
17
+
18
+ assert_equal :data_module, target2.qualified_key
19
+ assert_equal :data_module, target2.key
20
+ assert_equal :repository, target2.container_key
21
+ assert_equal 'data_modules', target2.access_method
22
+ assert_equal nil, target2.facet_key
23
+ assert_equal true, target2.standard?
24
+
25
+ target3 = Reality::Generators::Target.new(target_manager, :entrypoint, :repository, :facet_key => :gwt)
26
+
27
+ assert_equal :'gwt.entrypoint', target3.qualified_key
28
+ assert_equal :entrypoint, target3.key
29
+ assert_equal :repository, target3.container_key
30
+ assert_equal 'entrypoints', target3.access_method
31
+ assert_equal :gwt, target3.facet_key
32
+ assert_equal false, target3.standard?
33
+
34
+ target4 = Reality::Generators::Target.new(target_manager, :persistence_unit, :repository, :facet_key => :jpa, :access_method => 'standard_persistence_units')
35
+
36
+ assert_equal :'jpa.persistence_unit', target4.qualified_key
37
+ assert_equal :persistence_unit, target4.key
38
+ assert_equal :repository, target4.container_key
39
+ assert_equal 'standard_persistence_units', target4.access_method
40
+ assert_equal :jpa, target4.facet_key
41
+ assert_equal false, target4.standard?
42
+
43
+ target1 = Reality::Generators::Target.new(target_manager, :project, nil, :access_method => 'project_set')
44
+
45
+ assert_equal :project, target1.qualified_key
46
+ assert_equal :project, target1.key
47
+ assert_equal nil, target1.container_key
48
+ assert_equal 'project_set', target1.access_method
49
+ assert_equal nil, target1.facet_key
50
+ assert_equal true, target1.standard?
51
+
52
+ assert_raise_message('Attempting to redefine target project') { Reality::Generators::Target.new(target_manager, :project, nil, {}) }
53
+
54
+ assert_raise_message("Target 'foo' defines container as 'bar' but no such target exists.") { Reality::Generators::Target.new(target_manager, :foo, :bar, {}) }
55
+ end
56
+
57
+ def test_target_manager_basic_operation
58
+
59
+ target_manager = Reality::Generators::TargetManager.new(TestTemplateSetContainer)
60
+
61
+ assert_equal false, target_manager.is_target_valid?(:project)
62
+ assert_equal [], target_manager.target_keys
63
+ assert_equal false, target_manager.target_by_key?(:project)
64
+
65
+ target_manager.target(:project)
66
+
67
+ assert_equal true, target_manager.is_target_valid?(:project)
68
+ assert_equal [:project], target_manager.target_keys
69
+ assert_equal true, target_manager.target_by_key?(:project)
70
+ assert_equal 1, target_manager.targets.size
71
+ assert_equal :project, target_manager.targets[0].key
72
+
73
+ target_manager.target(:component, :project, :facet_key => :jsc, :access_method => 'comps')
74
+
75
+ assert_equal true, target_manager.is_target_valid?(:'jsc.component')
76
+ assert_equal true, target_manager.target_by_key?(:'jsc.component')
77
+ assert_equal 2, target_manager.targets.size
78
+ target = target_manager.target_by_key(:'jsc.component')
79
+ assert_equal :component, target.key
80
+ assert_equal :project, target.container_key
81
+ assert_equal :jsc, target.facet_key
82
+ assert_equal 'comps', target.access_method
83
+
84
+ assert_equal 1, target_manager.targets_by_container(:project).size
85
+ assert_equal :component, target_manager.targets_by_container(:project)[0].key
86
+
87
+ assert_raise_message("Can not find target with key 'foo'") { target_manager.target_by_key(:foo) }
88
+ end
89
+ end