asciidoctor-templates-compiler 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 284ae9f82eaa132717e6fbb51d7bb84fb5814a6a
4
+ data.tar.gz: 7330fa5e9a09c109082a406f283e7961578943d3
5
+ SHA512:
6
+ metadata.gz: ce6e27c02ec9a9d3fea1ebb00d51986fdbbb0546916ca94c157b89d2eb6d6a9f8743d649d7bded06dedb73683c1d13754507831874d2f2dc952189433e9b8032
7
+ data.tar.gz: 6eef241dfe9d24f2fdfe8679508a8261cf062c411d9b651222a76e4065ab165472e20b0a252860de72625e48ff3aa49e3a2accf3c56a2aff15c771f0babbee6d
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright 2017 Jakub Jirutka <jakub@jirutka.cz>.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.adoc ADDED
@@ -0,0 +1,62 @@
1
+ = Asciidoctor Templates Compiler
2
+ :source-language: ruby
3
+ // custom
4
+ :gem-name: asciidoctor-templates-compiler
5
+ :gem-version: 0.1.2
6
+
7
+ ifdef::env-github[]
8
+ image:https://img.shields.io/gem/v/{gem-name}.svg?style=flat[Gem Version, link="https://rubygems.org/gems/{gem-name}"]
9
+ endif::env-github[]
10
+
11
+ This tool allows to precompile Slim templates into Ruby code and assemble them into a single-file pure Ruby converter (backend).
12
+
13
+ TODO
14
+
15
+
16
+ == Installation
17
+
18
+ Add this line to your application’s Gemfile:
19
+
20
+ [source, subs="+attributes"]
21
+ group :development do
22
+ gem '{gem-name}', '~> {gem-version}'
23
+ end
24
+
25
+ or to your gemspec:
26
+
27
+ [source, subs="+attributes"]
28
+ s.add_development_dependency '{gem-name}', '~> {gem-version}'
29
+
30
+ and then execute:
31
+
32
+ [source, sh]
33
+ $ bundle install
34
+
35
+
36
+ == Usage
37
+
38
+ [source, subs="+attributes"]
39
+ ----
40
+ require '{gem-name}'
41
+
42
+ File.open('html_custom_converter.rb', 'w') do |file|
43
+ Asciidoctor::TemplatesCompiler::Slim.compile_converter(
44
+ templates_dir: 'data/templates',
45
+ class_name: 'HtmlCustomConverter',
46
+ delegate_backend: 'html5',
47
+ register_for: ['html-custom'],
48
+ backend_info: {
49
+ basebackend: 'html',
50
+ outfilesuffix: '.html',
51
+ filetype: 'html',
52
+ },
53
+ pretty: true,
54
+ output: file)
55
+ end
56
+ ----
57
+
58
+
59
+ == License
60
+
61
+ This project is licensed under http://opensource.org/licenses/MIT/[MIT License].
62
+ For the full text of the license, see the link:LICENSE[LICENSE] file.
@@ -0,0 +1,21 @@
1
+ require File.expand_path('../lib/asciidoctor/templates_compiler/version', __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'asciidoctor-templates-compiler'
5
+ s.version = Asciidoctor::TemplatesCompiler::VERSION
6
+ s.author = 'Jakub Jirutka'
7
+ s.email = 'jakub@jirutka.cz'
8
+ s.homepage = 'https://github.com/jirutka/asciidoctor-templates-compiler'
9
+ s.license = 'MIT'
10
+
11
+ s.summary = 'Compile templates-based Asciidoctor converter (backend) into a single Ruby file'
12
+
13
+ s.files = Dir['lib/**/*', '*.gemspec', 'LICENSE*', 'README*']
14
+
15
+ s.required_ruby_version = '>= 2.3'
16
+
17
+ s.add_runtime_dependency 'asciidoctor', '~> 1.5'
18
+ s.add_runtime_dependency 'corefines', '~> 1.2'
19
+ s.add_runtime_dependency 'slim', '>= 2.1', '< 4.0'
20
+ s.add_runtime_dependency 'ruby-beautify', '~> 0.97'
21
+ end
@@ -0,0 +1 @@
1
+ require 'asciidoctor/templates_compiler'
@@ -0,0 +1,3 @@
1
+ require 'asciidoctor/templates_compiler/version'
2
+ require 'asciidoctor/templates_compiler/base'
3
+ require 'asciidoctor/templates_compiler/slim'
@@ -0,0 +1,73 @@
1
+ require 'asciidoctor/templates_compiler/version'
2
+ require 'asciidoctor/templates_compiler/converter_generator'
3
+ require 'asciidoctor/templates_compiler/ruby_beautify'
4
+ require 'stringio'
5
+
6
+ module Asciidoctor::TemplatesCompiler
7
+ class Base
8
+
9
+ class << self
10
+ def compile_converter(**opts)
11
+ new.compile_converter(**opts)
12
+ end
13
+
14
+ alias_method :call, :compile_converter
15
+ end
16
+
17
+
18
+ def compile_converter(output: StringIO.new, templates_dir:, pretty: false, **opts)
19
+ unless Dir.exists? templates_dir
20
+ fail "Templates directory '#{templates_dir}' does not exist"
21
+ end
22
+
23
+ backend_info = opts[:backend_info] || {}
24
+ templates = find_templates(templates_dir)
25
+ transforms_code = compile_templates(templates, backend_info: backend_info, pretty: pretty)
26
+
27
+ generate_class(output: output, transforms_code: transforms_code,
28
+ helpers_code: read_helpers(templates_dir), **opts)
29
+ end
30
+
31
+ alias_method :call, :compile_converter
32
+
33
+
34
+ protected
35
+
36
+ def compile_template(filename, backend_info: {})
37
+ fail NotImplementedError
38
+ end
39
+
40
+ def find_templates(dirname)
41
+ fail NotImplementedError
42
+ end
43
+
44
+
45
+ def beautify_code(code, **opts)
46
+ RubyBeautify.call(code, **opts)
47
+ end
48
+
49
+ def compile_templates(template_files, backend_info: {}, pretty: false)
50
+ template_files.lazy.map do |path|
51
+ code = compile_template(path, backend_info: backend_info)
52
+ code = beautify_code(code) if pretty
53
+
54
+ [transform_name_from_tmpl_name(path), code]
55
+ end
56
+ end
57
+
58
+ def generate_class(**opts)
59
+ ConverterGenerator.call(**opts)
60
+ end
61
+
62
+ def read_helpers(templates_dir)
63
+ path = File.join(templates_dir, 'helpers.rb')
64
+ IO.read(path) if File.exists? path
65
+ end
66
+
67
+ def transform_name_from_tmpl_name(filename)
68
+ File.basename(filename)
69
+ .sub(/\..*$/, '')
70
+ .sub(/^block_/, '')
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,167 @@
1
+ require 'asciidoctor/templates_compiler/version'
2
+ require 'corefines'
3
+ require 'stringio'
4
+
5
+ module Asciidoctor::TemplatesCompiler
6
+ class ConverterGenerator
7
+ using Corefines::String::indent
8
+
9
+ class << self
10
+ def generate(output: nil, **opts)
11
+ new(**opts).call(output)
12
+ end
13
+
14
+ alias_method :call, :generate
15
+ end
16
+
17
+
18
+ def initialize(class_name:, transforms_code:, helpers_code: nil,
19
+ register_for: [], backend_info: {}, delegate_backend: nil, **_)
20
+ @class_name = class_name
21
+ @transforms_code = transforms_code
22
+ @helpers_code = helpers_code
23
+ @register_for = register_for
24
+ @backend_info = backend_info
25
+ @delegate_backend = delegate_backend
26
+ end
27
+
28
+ def generate(out = StringIO.new)
29
+ out << head_code << "\n"
30
+ out << helpers_code << "\n" if @helpers_code
31
+ out << initialization_code << "\n"
32
+ out << convert_method_code << "\n"
33
+ transform_methods_code(out)
34
+ out << support_methods_code << "\n"
35
+ out << tail_code
36
+ out
37
+ end
38
+
39
+ alias_method :call, :generate
40
+
41
+ protected
42
+
43
+ def head_code
44
+ init_modules = @class_name
45
+ .split('::')[0..-2]
46
+ .map { |name| "module #{name};"}
47
+ .tap { |ary| ary.push('end ' * ary.size) }
48
+ .join(' ').strip
49
+
50
+ <<~EOF
51
+ # This file has been generated!
52
+
53
+ #{init_modules}
54
+ class #{@class_name} < ::Asciidoctor::Converter::Base
55
+ EOF
56
+ end
57
+
58
+ def helpers_code
59
+ <<~EOF.indent(2, ' ')
60
+ #{separator 'Begin of Helpers'}
61
+ #{@helpers_code}
62
+
63
+ # Make Helpers' constants accessible from transform methods.
64
+ Helpers.constants.each do |const|
65
+ const_set(const, Helpers.const_get(const))
66
+ end
67
+
68
+ #{separator 'End of Helpers'}
69
+ EOF
70
+ end
71
+
72
+ def initialization_code
73
+ setup_backend_info = @backend_info
74
+ .map { |k, v| " #{k} #{v.inspect}" }.join("\n")
75
+
76
+ if !@register_for.empty?
77
+ register_for = "register_for #{@register_for.map(&:inspect).join(', ')}\n"
78
+ end
79
+
80
+ if @delegate_backend
81
+ delegate_converter = <<~EOF.rstrip.indent(2, ' ')
82
+
83
+ delegate_backend = (opts[:delegate_backend] || #{@delegate_backend.inspect}).to_s
84
+ factory = ::Asciidoctor::Converter::Factory
85
+
86
+ converter = factory.create(delegate_backend, backend_info)
87
+ @delegate_converter = if converter == self
88
+ factory.new.create(delegate_backend, backend_info)
89
+ else
90
+ converter
91
+ end
92
+ EOF
93
+ end
94
+
95
+ [
96
+ register_for,
97
+ 'def initialize(backend, opts = {})',
98
+ ' super',
99
+ setup_backend_info,
100
+ delegate_converter,
101
+ 'end',
102
+ '',
103
+ ].compact.join("\n").indent(2, ' ')
104
+ end
105
+
106
+ def convert_method_code
107
+ converter = if @delegate_backend
108
+ 'respond_to?(transform) ? self : @delegate_converter'
109
+ else
110
+ 'self'
111
+ end
112
+
113
+ <<~EOF.indent(2, ' ')
114
+ def convert(node, transform = nil, opts = {})
115
+ transform ||= node.node_name
116
+ converter = #{converter}
117
+
118
+ if opts.empty?
119
+ converter.send(transform, node)
120
+ else
121
+ converter.send(transform, node, opts)
122
+ end
123
+ end
124
+ EOF
125
+ end
126
+
127
+ def support_methods_code
128
+ <<~EOF.indent(2, ' ')
129
+ def set_local_variables(binding, vars)
130
+ vars.each do |key, val|
131
+ binding.local_variable_set(key.to_sym, val)
132
+ end
133
+ end
134
+ EOF
135
+ end
136
+
137
+ def transform_methods_code(out)
138
+ out << " #{separator 'Begin of generated transformation methods'}"
139
+
140
+ @transforms_code.each do |name, code|
141
+ out << <<~EOF.indent(2, ' ')
142
+
143
+ def #{name}(node, opts = {})
144
+ node.extend(Helpers)
145
+ node.instance_eval do
146
+ converter.set_local_variables(binding, opts) unless opts.empty?
147
+ #{code.indent(4, ' ')}
148
+ end
149
+ end
150
+ EOF
151
+ end
152
+
153
+ out << " #{separator 'End of generated transformation methods'}\n"
154
+ end
155
+
156
+ def tail_code
157
+ "end\n"
158
+ end
159
+
160
+ private
161
+
162
+ def separator(title)
163
+ dashes = '-' * ((76 - title.length) / 2)
164
+ "##{dashes} #{title} #{dashes}#\n"
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,27 @@
1
+ require 'asciidoctor/templates_compiler/version'
2
+ require 'ruby-beautify'
3
+
4
+ module Asciidoctor::TemplatesCompiler
5
+ module RubyBeautify
6
+ extend self
7
+
8
+ def pretty_string(code, indent_count: 2)
9
+ new_lines_old = ::RubyBeautify::NEW_LINES
10
+ ::RubyBeautify::NEW_LINES.push(:on_semicolon) # XXX: sandbox somehow?
11
+
12
+ s = "def __\n#{code}\nend\n"
13
+ s.gsub! /^;/, '' # remove leading semicolons
14
+ s.gsub! /;\s*$/, '' # remove trailing semicolons
15
+ s.replace ::RubyBeautify.pretty_string(s, indent_token: "\1", indent_count: indent_count)
16
+ s.gsub! ";\1", "\n\1" # remove trailing semicolons after formatting
17
+ s.gsub! "\1", ' ' # replace placeholder indent char with space
18
+ s.sub! /\Adef __\n/, '' # remove wrapper method
19
+ s.sub! /\nend\n\z/, '' # remove wrapper method
20
+
21
+ ::RubyBeautify::NEW_LINES.replace(new_lines_old) # XXX: not thread-safe
22
+ s
23
+ end
24
+
25
+ alias :call :pretty_string
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ require 'asciidoctor/converter'
2
+ require 'asciidoctor/converter/template'
3
+ require 'asciidoctor/templates_compiler/version'
4
+ require 'asciidoctor/templates_compiler/base'
5
+ require 'corefines'
6
+ require 'slim'
7
+ require 'slim/include'
8
+
9
+ module Asciidoctor::TemplatesCompiler
10
+ class Slim < Base
11
+ using Corefines::Object::then
12
+
13
+ protected
14
+
15
+ def compile_template(filename, backend_info: {})
16
+ htmlsyntax = backend_info[:htmlsyntax] || backend_info['htmlsyntax'] || :html
17
+ opts = engine_options.merge(file: filename, format: htmlsyntax.to_sym)
18
+ content = IO.read(filename)
19
+
20
+ ::Slim::Engine.new(opts).call(content).tap do |code|
21
+ code.scan(/::(?:Slim|Temple)(?:\:\:\w+)*/).uniq.each do |name|
22
+ $stderr.puts "WARNING: Compiled template '#{filename}' references constant #{name}"
23
+ end
24
+ end
25
+ end
26
+
27
+ def find_templates(dirname)
28
+ Dir.glob("#{dirname}/[^_]*.slim")
29
+ end
30
+
31
+ def read_helpers(templates_dir)
32
+ super.then { |s| s.sub('module Slim::Helpers', 'module Helpers') }
33
+ end
34
+
35
+ def engine_options
36
+ ::Asciidoctor::Converter::TemplateConverter::DEFAULT_ENGINE_OPTIONS[:slim]
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ module Asciidoctor
2
+ module TemplatesCompiler
3
+ VERSION = '0.1.2'
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: asciidoctor-templates-compiler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Jakub Jirutka
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-08-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: asciidoctor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: corefines
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: slim
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '2.1'
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: '4.0'
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '2.1'
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '4.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: ruby-beautify
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.97'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.97'
75
+ description:
76
+ email: jakub@jirutka.cz
77
+ executables: []
78
+ extensions: []
79
+ extra_rdoc_files: []
80
+ files:
81
+ - LICENSE
82
+ - README.adoc
83
+ - asciidoctor-templates-compiler.gemspec
84
+ - lib/asciidoctor-templates-compiler.rb
85
+ - lib/asciidoctor/templates_compiler.rb
86
+ - lib/asciidoctor/templates_compiler/base.rb
87
+ - lib/asciidoctor/templates_compiler/converter_generator.rb
88
+ - lib/asciidoctor/templates_compiler/ruby_beautify.rb
89
+ - lib/asciidoctor/templates_compiler/slim.rb
90
+ - lib/asciidoctor/templates_compiler/version.rb
91
+ homepage: https://github.com/jirutka/asciidoctor-templates-compiler
92
+ licenses:
93
+ - MIT
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '2.3'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.6.11
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Compile templates-based Asciidoctor converter (backend) into a single Ruby
115
+ file
116
+ test_files: []