asciidoctor-templates-compiler 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
  - - ">="