asciidoctor-templates-compiler 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad02dd81d47a7185c55b040d6a80af3f6fa5ba24
4
- data.tar.gz: 26b3aaa536e7f76843fa4f7036c9d8d1901e4453
3
+ metadata.gz: 51590b253d877005f5760f154c14346665e1722c
4
+ data.tar.gz: 9d98b848da5104228aa0c8918e9646b12ec06805
5
5
  SHA512:
6
- metadata.gz: 5190bb978d148d33659d16ce2065f6455e7da03322fe8c45979403ef6f4fc1f60baf27765d5900e16d04019466ff3e55169301172f897715d55772d903f1423e
7
- data.tar.gz: 27cb8c19f213138b057d998d8f1a53eae0a03798ba0d508053ae651750ecbeec2b321d3d922bf4ef32db521c3b36b7ff34d9120f2400ecccafa6147563c391e5
6
+ metadata.gz: 3c6d38f6a691c349843ca8fd9d9569e6ac125bc81cb3732a45d3af1c4b651d7d953b8d759151823dbb6f1f3cb7802330719bab51e472fa04e0529674ca5c638a
7
+ data.tar.gz: 675c48c88d2c797049857cc70bedb7e3e56f9ec666ae8f2fa3181aafdfea67cc51fb949cd31f20240f27867d899b1dac0cfeb4b752188a026562c7104e1d667f
@@ -2,7 +2,7 @@
2
2
  :source-language: ruby
3
3
  // custom
4
4
  :gem-name: asciidoctor-templates-compiler
5
- :gem-version: 0.2.0
5
+ :gem-version: 0.3.0
6
6
  :gh-name: jirutka/{gem-name}
7
7
  :gh-branch: master
8
8
  :codacy-id: b23b8c6503474ea5b13537eaef0c73d5
@@ -11,11 +11,13 @@ Gem::Specification.new do |s|
11
11
  s.summary = 'Compile templates-based Asciidoctor converter (backend) into a single Ruby file'
12
12
 
13
13
  s.files = Dir['lib/**/*', '*.gemspec', 'LICENSE*', 'README*']
14
+ s.executables = Dir['bin/*'].map { |f| File.basename(f) }
14
15
 
15
- s.required_ruby_version = '>= 2.3'
16
+ s.required_ruby_version = '>= 2.1'
16
17
 
17
18
  s.add_runtime_dependency 'asciidoctor', '~> 1.5'
18
19
  s.add_runtime_dependency 'corefines', '~> 1.2'
20
+ s.add_runtime_dependency 'docopt', '~> 0.6'
19
21
  s.add_runtime_dependency 'slim', '>= 2.1', '< 4.0'
20
22
  s.add_runtime_dependency 'ruby-beautify', '~> 0.97'
21
23
 
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ require 'asciidoctor/templates_compiler'
4
+ require 'docopt'
5
+ require 'corefines'
6
+
7
+ using Corefines::Hash::rekey
8
+ using Corefines::String::unindent
9
+
10
+ PROG_NAME = 'asciidoctor-templates-compiler'
11
+ BUGS_URL = "https://github.com/jirutka/#{PROG_NAME}/issues"
12
+
13
+ HELP_MSG = <<-EOF.unindent
14
+ Usage:
15
+ #{PROG_NAME} [options...] TEMPLATES_DIR
16
+ #{PROG_NAME} --help | --version
17
+
18
+ Arguments:
19
+ TEMPLATES_DIR Path of the directory where to look for templates ("*.slim"
20
+ files not starting with "_", in the case of Slim) and
21
+ (optional) "helpers.rb".
22
+
23
+ Options:
24
+ -b --backend-info KEY=VAL[,...] Parameters for backend_info: basebackend, outfilesuffix,
25
+ filetype, and htmlsyntax.
26
+
27
+ -n --class-name NAME Full name of the converter class to generate (e.g.
28
+ My::HTML::Converter) [default: Converter].
29
+
30
+ -d --delegate-backend BACKEND Name of the backend (converter) to use as a fallback for AST
31
+ nodes not supported by your converter. If not specified
32
+ (default), no fallback will be used and converter will raise
33
+ "NoMethodError" when it try to convert an unsupported node.
34
+
35
+ -o --output FILE Where to write the output. Use "-" for stdout. [default: -]
36
+
37
+ -P --no-pretty Do not format generated Ruby code.
38
+
39
+ -r --register-for BACKEND[,...] Backend name(s) that the generated converter should be
40
+ registered in Asciidoctor to handle.
41
+
42
+ -V --version Print version and exit.
43
+
44
+ -h --help Show this message and exit.
45
+
46
+ Please report bugs at <#{BUGS_URL}>.
47
+ EOF
48
+
49
+ def die(message, status: 1)
50
+ $stderr.puts("#{PROG_NAME}: #{message}")
51
+ exit status
52
+ end
53
+
54
+ def parse_kw_list(list)
55
+ list
56
+ .flat_map { |arg| arg.split(/\s*,\s*/) }
57
+ .map { |item| item.split('=', 2) }
58
+ .to_h
59
+ rescue ArgumentError
60
+ raise ArgumentError, 'not a list of key=word arguments'
61
+ end
62
+
63
+ def parse_option_value(name, value)
64
+ case name
65
+ when :backend_info
66
+ parse_kw_list(value)
67
+ when :class_name, :delegate_backend, :output
68
+ value.last
69
+ when :pretty
70
+ value.zero?
71
+ else
72
+ value
73
+ end
74
+ rescue ArgumentError => e
75
+ raise ArgumentError, "Invalid option --#{name}: #{e.message}"
76
+ end
77
+
78
+ opts = begin
79
+ Docopt::docopt(HELP_MSG, help: false)
80
+ .rekey { |key| key.sub(/^--/, '').tr('-', '_').downcase.to_sym }
81
+ .rekey(:no_pretty => :pretty) # rubocop:disable Style/HashSyntax
82
+ .map { |k, v| [k, parse_option_value(k, v)] }.to_h
83
+ rescue Docopt::Exit => e
84
+ $stderr.puts(e.message)
85
+ exit 1
86
+ rescue ArgumentError => e
87
+ die e.message
88
+ end
89
+
90
+ if opts[:help]
91
+ puts HELP_MSG.strip
92
+
93
+ elsif opts[:version]
94
+ puts [PROG_NAME, Asciidoctor::TemplatesCompiler::VERSION].join(' ')
95
+
96
+ else
97
+ output = if opts[:output] == '-'
98
+ $stdout
99
+ else
100
+ File.open(opts[:output], 'w')
101
+ end
102
+
103
+ begin
104
+ Asciidoctor::TemplatesCompiler::Slim.compile_converter(**opts, output: output)
105
+ rescue RuntimeError => e
106
+ die e.message
107
+ ensure
108
+ output.close if output != $stdout
109
+ end
110
+ end
@@ -5,8 +5,12 @@ require 'asciidoctor/templates_compiler/ruby_beautify'
5
5
  require 'stringio'
6
6
 
7
7
  module Asciidoctor::TemplatesCompiler
8
+ ##
9
+ # Base class for templates compilers.
8
10
  class Base
9
11
  class << self
12
+ ##
13
+ # An "alias" for {#compile_converter}.
10
14
  def compile_converter(**opts)
11
15
  new.compile_converter(**opts)
12
16
  end
@@ -14,9 +18,23 @@ module Asciidoctor::TemplatesCompiler
14
18
  alias call compile_converter
15
19
  end
16
20
 
21
+ ##
22
+ # (see ConverterGenerator.generate)
23
+ #
24
+ # Compiles templates found in _templates_dir_ to Ruby and generates an Asciidoctor converter
25
+ # class from them.
26
+ #
27
+ # @param templates_dir [String] path of the directory where to look for templates
28
+ # and (optional) +helpers.rb+.
29
+ # @param engine_opts [Hash] a hash of options to pass into the templating engine.
30
+ # Default is empty.
31
+ # @param pretty [Boolean] enable pretty-formatting of the generated Ruby code?
32
+ #
33
+ # @raise [ArgumentError] if the given _templates_dir_ does not exist.
34
+ #
17
35
  def compile_converter(templates_dir:, engine_opts: {}, pretty: false, **opts)
18
36
  unless Dir.exist? templates_dir
19
- raise "Templates directory '#{templates_dir}' does not exist"
37
+ raise ArgumentError, "Templates directory '#{templates_dir}' does not exist"
20
38
  end
21
39
 
22
40
  templates = find_templates(templates_dir)
@@ -30,11 +48,20 @@ module Asciidoctor::TemplatesCompiler
30
48
 
31
49
  protected
32
50
 
51
+ ##
33
52
  # @abstract
53
+ # @param filename [String] path of the template file to compile.
54
+ # @param engine_opts [Hash] a hash of options to pass into the templating engine.
55
+ # @return [String] a Ruby code of the compiled template.
56
+ #
34
57
  def compile_template(filename, engine_opts = {})
35
58
  end
36
59
 
60
+ ##
37
61
  # @abstract
62
+ # @param dirname [String] path of the directory where to look for templates.
63
+ # @return [Array<String>] paths of the found template files.
64
+ #
38
65
  def find_templates(dirname)
39
66
  end
40
67
 
@@ -1,21 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
  require 'asciidoctor/templates_compiler/version'
3
+ require 'asciidoctor/templates_compiler/string_ext'
3
4
  require 'corefines'
4
5
  require 'stringio'
5
6
 
6
7
  module Asciidoctor::TemplatesCompiler
8
+ ##
9
+ # Source-code generator of Asciidoctor converter classes.
7
10
  class ConverterGenerator
8
- using Corefines::String::indent
11
+ using Corefines::String[:indent, :unindent]
9
12
  using Corefines::Object::blank?
13
+ using StringExt::reindent
10
14
 
11
15
  class << self
16
+ ##
17
+ # (see #initialize)
18
+ # @param output [#<<] output stream where to write the generated class.
19
+ # Defaults to {StringIO}.
20
+ # @return the given _output_ stream.
21
+ #
12
22
  def generate(output: StringIO.new, **opts)
13
23
  new(**opts).call(output)
14
24
  end
15
25
 
26
+ # An alias for {.generate}.
16
27
  alias call generate
17
28
  end
18
29
 
30
+ ##
31
+ # @param class_name [String] full name of the converter class to generate
32
+ # (e.g. +My::HTML::Converter+).
33
+ # @param transforms_code [#each] enumerable that yields pair: transform name ()
34
+ # @param helpers_code [String, nil] source code to include in the generated class. It must
35
+ # contain a module named +Helpers+.
36
+ # @param register_for [Array<String>] an array of backend names that the generated converter
37
+ # should be registered for to handle. Default is empty.
38
+ # @param backend_info [Hash] a hash of parameters for +backend_info+: +basebackend+,
39
+ # +outfilesuffix+, +filetype+, +htmlsyntax+. Default is empty.
40
+ # @param delegate_backend [String, nil] name of the backend (converter) to use as a fallback
41
+ # for AST nodes not supported by the generated converter. If not specified, no fallback will
42
+ # be used and converter will raise +NoMethodError+ when it try to convert unsupported node.
43
+ #
44
+ # @raise [ArgumentError] if _helpers_code_ is not blank and does not contain module +Helpers+.
45
+ #
19
46
  def initialize(class_name:, transforms_code:, helpers_code: nil,
20
47
  register_for: [], backend_info: {}, delegate_backend: nil, **)
21
48
  @class_name = class_name
@@ -30,6 +57,12 @@ module Asciidoctor::TemplatesCompiler
30
57
  end
31
58
  end
32
59
 
60
+ ##
61
+ # Generates source code of a converter class for Asciidoctor.
62
+ #
63
+ # @param out [#<<] output stream where to write the generated class.
64
+ # @return the given _out_ stream.
65
+ #
33
66
  def generate(out = StringIO.new)
34
67
  out << head_code << "\n"
35
68
  out << helpers_code << "\n" unless @helpers_code.blank?
@@ -52,7 +85,7 @@ module Asciidoctor::TemplatesCompiler
52
85
  .tap { |ary| ary.push('end ' * ary.size) }
53
86
  .join(' ').strip
54
87
 
55
- <<~EOF
88
+ <<-EOF.unindent
56
89
  # This file has been generated!
57
90
 
58
91
  #{init_modules}
@@ -61,9 +94,9 @@ module Asciidoctor::TemplatesCompiler
61
94
  end
62
95
 
63
96
  def helpers_code
64
- <<~EOF.indent(2, ' ')
97
+ <<-EOF.unindent.%(@helpers_code).indent(2)
65
98
  #{separator 'Begin of Helpers'}
66
- #{@helpers_code}
99
+ %s
67
100
 
68
101
  # Make Helpers' constants accessible from transform methods.
69
102
  Helpers.constants.each do |const|
@@ -84,7 +117,7 @@ module Asciidoctor::TemplatesCompiler
84
117
  end
85
118
 
86
119
  if @delegate_backend
87
- delegate_converter = <<~EOF.rstrip.indent(2, ' ')
120
+ delegate_converter = <<-EOF.reindent(2).rstrip
88
121
 
89
122
  delegate_backend = (opts[:delegate_backend] || #{@delegate_backend.inspect}).to_s
90
123
  factory = ::Asciidoctor::Converter::Factory
@@ -106,7 +139,7 @@ module Asciidoctor::TemplatesCompiler
106
139
  delegate_converter,
107
140
  'end',
108
141
  '',
109
- ].compact.join("\n").indent(2, ' ')
142
+ ].compact.join("\n").indent(2)
110
143
  end
111
144
 
112
145
  def convert_method_code
@@ -116,7 +149,7 @@ module Asciidoctor::TemplatesCompiler
116
149
  'self'
117
150
  end
118
151
 
119
- <<~EOF.indent(2, ' ')
152
+ <<-EOF.reindent(2)
120
153
  def convert(node, transform = nil, opts = {})
121
154
  transform ||= node.node_name
122
155
  converter = #{converter}
@@ -131,7 +164,7 @@ module Asciidoctor::TemplatesCompiler
131
164
  end
132
165
 
133
166
  def support_methods_code
134
- <<~EOF.indent(2, ' ')
167
+ <<-EOF.reindent(2)
135
168
  def set_local_variables(binding, vars)
136
169
  vars.each do |key, val|
137
170
  binding.local_variable_set(key.to_sym, val)
@@ -141,19 +174,17 @@ module Asciidoctor::TemplatesCompiler
141
174
  end
142
175
 
143
176
  def transform_methods_code(out)
144
- out << " #{separator 'Begin of generated transformation methods'}"
177
+ out << " #{separator 'Begin of generated transformation methods'}\n"
145
178
 
146
179
  @transforms_code.each do |name, code|
147
- out << <<~EOF.indent(2, ' ')
148
-
149
- def #{name}(node, opts = {})
150
- #{' node.extend(Helpers)' unless @helpers_code.blank?}
151
- node.instance_eval do
152
- converter.set_local_variables(binding, opts) unless opts.empty?
153
- #{code.indent(6, ' ')}
154
- end
155
- end
156
- EOF
180
+ out << "\n"
181
+ out << " def #{name}(node, opts = {})\n"
182
+ out << " node.extend(Helpers)\n" unless @helpers_code.blank?
183
+ out << " node.instance_eval do\n"
184
+ out << " converter.set_local_variables(binding, opts) unless opts.empty?\n"
185
+ out << code.indent(6, ' ') << "\n"
186
+ out << " end\n"
187
+ out << " end\n"
157
188
  end
158
189
 
159
190
  out << " #{separator 'End of generated transformation methods'}\n"
@@ -14,7 +14,7 @@ module Asciidoctor::TemplatesCompiler
14
14
  new_lines_old = NEW_LINES
15
15
  NEW_LINES.push(:on_semicolon) # XXX: sandbox somehow?
16
16
 
17
- s = +"module M_\n#{code}\nend\n"
17
+ s = "module M_\n#{code}\nend\n".dup
18
18
  s.gsub!(/^[ \t]*;/, '') # remove leading semicolons
19
19
  s.gsub!(/;\s*$/, '') # remove trailing semicolons
20
20
  s.replace(pretty_string_orig(s, indent_token: "\1", indent_count: indent_count))
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ require 'corefines'
3
+
4
+ module Asciidoctor::TemplatesCompiler
5
+ # @private
6
+ module StringExt
7
+ module Reindent
8
+ refine ::String do
9
+ using ::Corefines::String[:indent, :unindent]
10
+
11
+ def reindent(level, indent_str = ' ')
12
+ unindent.indent!(level, indent_str)
13
+ end
14
+ end
15
+ end
16
+
17
+ include ::Corefines::Support::AliasSubmodules
18
+ end
19
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module TemplatesCompiler
5
- VERSION = '0.2.0'
5
+ VERSION = '0.3.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-templates-compiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Jirutka
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-04 00:00:00.000000000 Z
11
+ date: 2017-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: docopt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.6'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: slim
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -130,19 +144,22 @@ dependencies:
130
144
  version: '0.14'
131
145
  description:
132
146
  email: jakub@jirutka.cz
133
- executables: []
147
+ executables:
148
+ - asciidoctor-templates-compiler
134
149
  extensions: []
135
150
  extra_rdoc_files: []
136
151
  files:
137
152
  - LICENSE
138
153
  - README.adoc
139
154
  - asciidoctor-templates-compiler.gemspec
155
+ - bin/asciidoctor-templates-compiler
140
156
  - lib/asciidoctor-templates-compiler.rb
141
157
  - lib/asciidoctor/templates_compiler.rb
142
158
  - lib/asciidoctor/templates_compiler/base.rb
143
159
  - lib/asciidoctor/templates_compiler/converter_generator.rb
144
160
  - lib/asciidoctor/templates_compiler/ruby_beautify.rb
145
161
  - lib/asciidoctor/templates_compiler/slim.rb
162
+ - lib/asciidoctor/templates_compiler/string_ext.rb
146
163
  - lib/asciidoctor/templates_compiler/temple_ext.rb
147
164
  - lib/asciidoctor/templates_compiler/version.rb
148
165
  homepage: https://github.com/jirutka/asciidoctor-templates-compiler
@@ -157,7 +174,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
157
174
  requirements:
158
175
  - - ">="
159
176
  - !ruby/object:Gem::Version
160
- version: '2.3'
177
+ version: '2.1'
161
178
  required_rubygems_version: !ruby/object:Gem::Requirement
162
179
  requirements:
163
180
  - - ">="