reality-generators 1.0.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.
@@ -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