lib/asciidoctor/extensions.rb in asciidoctor-1.5.8 vs lib/asciidoctor/extensions.rb in asciidoctor-2.0.0.rc.1
- old
+ new
@@ -1,9 +1,8 @@
-# NOTE .to_s hides require from Opal
-require 'asciidoctor'.to_s unless defined? Asciidoctor
+# frozen_string_literal: true
+(require 'asciidoctor' unless defined? Asciidoctor.load) unless RUBY_ENGINE == 'opal'
-# encoding: UTF-8
module Asciidoctor
# Extensions provide a way to participate in the parsing and converting
# phases of the AsciiDoc processor or extend the AsciiDoc syntax.
#
# The various extensions participate in AsciiDoc processing as follows:
@@ -55,31 +54,27 @@
# Returns nothing
def option key, default_value
config[key] = default_value
end
- # Include the DSL class for this processor into this processor class or instance.
+ # Mixes the DSL class for this processor into this processor class or instance.
#
- # This method automatically detects whether to use the include or extend keyword
- # based on what is appropriate.
+ # This method automatically detects whether to use the include or extend keyword to mix in the module.
#
# NOTE Inspiration for this DSL design comes from https://corcoran.io/2013/09/04/simple-pattern-ruby-dsl/
#
- # Returns nothing
- def use_dsl
- if self.name.nil_or_empty?
- # NOTE contants(false) doesn't exist in Ruby 1.8.7
- #include const_get :DSL if constants(false).grep :DSL
- include const_get :DSL if constants.grep :DSL
- else
- # NOTE contants(false) doesn't exist in Ruby 1.8.7
- #extend const_get :DSL if constants(false).grep :DSL
- extend const_get :DSL if constants.grep :DSL
+ # Returns self
+ def enable_dsl
+ if const_defined? :DSL
+ if singleton_class?
+ include const_get :DSL
+ else
+ extend const_get :DSL
+ end
end
end
- alias extend_dsl use_dsl
- alias include_dsl use_dsl
+ alias use_dsl enable_dsl
end
# Public: Get the configuration Hash for this processor instance.
attr_reader :config
@@ -90,11 +85,11 @@
def update_config config
@config.update config
end
def process *args
- raise ::NotImplementedError, %(Asciidoctor::Extensions::Processor subclass must implement ##{__method__} method)
+ raise ::NotImplementedError, %(#{Processor} subclass #{self.class} must implement the ##{__method__} method)
end
# QUESTION should attributes be an option instead of a parameter?
# Public: Creates a new Section node.
@@ -154,11 +149,11 @@
sect.update_attributes attrs
sect
end
def create_block parent, context, source, attrs, opts = {}
- Block.new parent, context, { :source => source, :attributes => attrs }.merge(opts)
+ Block.new parent, context, { source: source, attributes: attrs }.merge(opts)
end
# Public: Creates a list node and links it to the specified parent.
#
# parent - The parent Block (Block, Section, or Document) of this new list block.
@@ -248,24 +243,24 @@
end
def process *args, &block
if block_given?
raise ::ArgumentError, %(wrong number of arguments (given #{args.size}, expected 0)) unless args.empty?
+ unless block.binding && self == block.binding.receiver
+ # NOTE remap self in process method to processor instance
+ context = self
+ block.define_singleton_method(:call) {|*m_args| context.instance_exec(*m_args, &block) }
+ end
@process_block = block
# TODO enable if we want to support passing proc or lambda as argument instead of block
#elsif ::Proc === args[0]
- # block = args.shift
- # raise ::ArgumentError, %(wrong number of arguments (given #{args.size}, expected 0)) unless args.empty?
- # @process_block = block
+ # raise ::ArgumentError, %(wrong number of arguments (given #{args.size - 1}, expected 0)) unless args.size == 1
+ # @process_block = args.shift
elsif defined? @process_block
- # NOTE Proc automatically expands a single array argument
- # ...but lambda doesn't (and we want to accept lambdas too)
- # TODO need a test for this!
@process_block.call(*args)
else
- # TODO add exception message here
- raise ::NotImplementedError
+ raise ::NotImplementedError, %(#{self.class} ##{__method__} method called before being registered)
end
end
def process_block_given?
defined? @process_block
@@ -289,32 +284,29 @@
@name = value
else
option :name, value
end
end
- # NOTE match_name may get deprecated
- alias match_name named
def content_model value
option :content_model, value
end
alias parse_content_as content_model
- alias parses_content_as content_model
- #alias parse_as content_model
- #alias parsed_as content_model
- def positional_attrs *value
+ def positional_attributes *value
option :pos_attrs, value.flatten
end
- alias name_attributes positional_attrs
- alias name_positional_attributes positional_attrs
+ alias name_positional_attributes positional_attributes
+ # NOTE positional_attrs alias is deprecated
+ alias positional_attrs positional_attributes
def default_attrs value
option :default_attrs, value
end
+ alias default_attributes default_attrs
- def resolves_attributes *args
+ def resolve_attributes *args
# NOTE assume true as default value; rewrap single-argument string or symbol
if (args = args.fetch 0, true).respond_to? :to_sym
args = [args]
end unless args.size > 1
case args
@@ -323,19 +315,19 @@
option :default_attrs, {}
when ::Array
names, defaults = [], {}
args.each do |arg|
if (arg = arg.to_s).include? '='
- name, value = arg.split '=', 2
+ name, _, value = arg.partition '='
if name.include? ':'
- idx, name = name.split ':', 2
+ idx, _, name = name.partition ':'
idx = idx == '@' ? names.size : idx.to_i
names[idx] = name
end
defaults[name] = value
elsif arg.include? ':'
- idx, name = arg.split ':', 2
+ idx, _, name = arg.partition ':'
idx = idx == '@' ? names.size : idx.to_i
names[idx] = name
else
names << arg
end
@@ -344,11 +336,11 @@
option :default_attrs, defaults
when ::Hash
names, defaults = [], {}
args.each do |key, val|
if (name = key.to_s).include? ':'
- idx, name = name.split ':', 2
+ idx, _, name = name.partition ':'
idx = idx == '@' ? names.size : idx.to_i
names[idx] = name
end
defaults[name] = val if val
end
@@ -356,12 +348,12 @@
option :default_attrs, defaults
else
raise ::ArgumentError, %(unsupported attributes specification for macro: #{args.inspect})
end
end
- # NOTE we may decide to drop this alias
- alias resolve_attributes resolves_attributes
+ # NOTE resolves_attributes alias is deprecated
+ alias resolves_attributes resolve_attributes
end
# Public: Preprocessors are run after the source text is split into lines and
# normalized, but before parsing begins.
#
@@ -375,11 +367,11 @@
# falsy, which is equivalent) or a reference to a substitute Reader.
#
# Preprocessor implementations must extend the Preprocessor class.
class Preprocessor < Processor
def process document, reader
- raise ::NotImplementedError, %(Asciidoctor::Extensions::Preprocessor subclass must implement ##{__method__} method)
+ raise ::NotImplementedError, %(#{Preprocessor} subclass #{self.class} must implement the ##{__method__} method)
end
end
Preprocessor::DSL = DocumentProcessorDsl
# Public: TreeProcessors are run on the Document after the source has been
@@ -392,11 +384,11 @@
# TreeProcessor implementations must extend TreeProcessor.
#--
# QUESTION should the tree processor get invoked after parse header too?
class TreeProcessor < Processor
def process document
- raise ::NotImplementedError, %(Asciidoctor::Extensions::TreeProcessor subclass must implement ##{__method__} method)
+ raise ::NotImplementedError, %(#{TreeProcessor} subclass #{self.class} must implement the ##{__method__} method)
end
end
TreeProcessor::DSL = DocumentProcessorDsl
# Alias deprecated class name for backwards compatibility
@@ -417,11 +409,11 @@
# document.
#
# Postprocessor implementations must Postprocessor.
class Postprocessor < Processor
def process document, output
- raise ::NotImplementedError, %(Asciidoctor::Extensions::Postprocessor subclass must implement ##{__method__} method)
+ raise ::NotImplementedError, %(#{Postprocessor} subclass #{self.class} must implement the ##{__method__} method)
end
end
Postprocessor::DSL = DocumentProcessorDsl
# Public: IncludeProcessors are used to process `include::<target>[]`
@@ -435,11 +427,11 @@
# IncludeProcessor implementations must extend IncludeProcessor.
#--
# TODO add file extension or regexp as shortcut for handles? method
class IncludeProcessor < Processor
def process document, reader, target, attributes
- raise ::NotImplementedError, %(Asciidoctor::Extensions::IncludeProcessor subclass must implement ##{__method__} method)
+ raise ::NotImplementedError, %(#{IncludeProcessor} subclass #{self.class} must implement the ##{__method__} method)
end
def handles? target
true
end
@@ -481,11 +473,11 @@
super config
@config[:location] ||= :head
end
def process document
- raise ::NotImplementedError, %(Asciidoctor::Extensions::DocinfoProcessor subclass must implement ##{__method__} method)
+ raise ::NotImplementedError, %(#{DocinfoProcessor} subclass #{self.class} must implement the ##{__method__} method)
end
end
module DocinfoProcessorDsl
include DocumentProcessorDsl
@@ -537,11 +529,11 @@
# QUESTION should the default content model be raw??
@config[:content_model] ||= :compound
end
def process parent, reader, attributes
- raise ::NotImplementedError, %(Asciidoctor::Extensions::BlockProcessor subclass must implement ##{__method__} method)
+ raise ::NotImplementedError, %(#{BlockProcessor} subclass #{self.class} must implement the ##{__method__} method)
end
end
module BlockProcessorDsl
include SyntaxProcessorDsl
@@ -549,11 +541,11 @@
def contexts *value
option :contexts, value.flatten.to_set
end
alias on_contexts contexts
alias on_context contexts
- alias bound_to contexts
+ alias bind_to contexts
end
BlockProcessor::DSL = BlockProcessorDsl
class MacroProcessor < Processor
attr_accessor :name
@@ -563,27 +555,27 @@
@name = name || @config[:name]
@config[:content_model] ||= :attributes
end
def process parent, target, attributes
- raise ::NotImplementedError, %(Asciidoctor::Extensions::MacroProcessor subclass must implement ##{__method__} method)
+ raise ::NotImplementedError, %(#{MacroProcessor} subclass #{self.class} must implement the ##{__method__} method)
end
end
module MacroProcessorDsl
include SyntaxProcessorDsl
- def resolves_attributes *args
+ def resolve_attributes *args
if args.size == 1 && !args[0]
option :content_model, :text
return
end
super
option :content_model, :attributes
end
- # NOTE we may decide to drop this alias
- alias resolve_attributes resolves_attributes
+ # NOTE resolves_attributes alias is deprecated
+ alias resolves_attributes resolve_attributes
end
# Public: BlockMacroProcessors are used to handle block macros that have a
# custom name.
#
@@ -620,20 +612,20 @@
end
module InlineMacroProcessorDsl
include MacroProcessorDsl
- def with_format value
+ def format value
option :format, value
end
- alias using_format with_format
+ alias match_format format
+ # NOTE using_format alias is deprecated
+ alias using_format format
- def matches value
+ def match value
option :regexp, value
end
- alias match matches
- alias matching matches
end
InlineMacroProcessor::DSL = InlineMacroProcessorDsl
# Public: Extension is a proxy object for an extension implementation such as
# a processor. It allows the preparation of the extension instance to be
@@ -963,11 +955,11 @@
#
# # as an DocinfoProcessor subclass
# docinfo_processor MetaRobotsDocinfoProcessor
#
# # as an instance of a DocinfoProcessor subclass with an explicit location
- # docinfo_processor JQueryDocinfoProcessor.new, :location => :footer
+ # docinfo_processor JQueryDocinfoProcessor.new, location: :footer
#
# # as a name of a DocinfoProcessor subclass
# docinfo_processor 'MetaRobotsDocinfoProcessor'
#
# # as a method block
@@ -1317,34 +1309,31 @@
private
def add_document_processor kind, args, &block
kind_name = kind.to_s.tr '_', ' '
kind_class_symbol = kind_name.split.map {|it| it.capitalize }.join.to_sym
- kind_class = Extensions.const_get kind_class_symbol
- kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol) : nil
+ kind_class = Extensions.const_get kind_class_symbol, false
+ kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol, false) : nil
kind_store = instance_variable_get(%(@#{kind}_extensions).to_sym) || instance_variable_set(%(@#{kind}_extensions).to_sym, [])
# style 1: specified as block
extension = if block_given?
config = resolve_args args, 1
- # TODO if block arity is 0, assume block is process method
- processor = kind_class.new config
- # NOTE class << processor idiom doesn't work in Opal
- #class << processor
- # include_dsl
- #end
- # NOTE kind_class.contants(false) doesn't exist in Ruby 1.8.7
- processor.extend kind_class.const_get :DSL if kind_class.constants.grep :DSL
- processor.instance_exec(&block)
- processor.freeze
+ (processor = kind_class.new config).singleton_class.enable_dsl
+ if block.arity == 0
+ processor.instance_exec(&block)
+ else
+ yield processor
+ end
unless processor.process_block_given?
raise ::ArgumentError, %(No block specified to process #{kind_name} extension at #{block.source_location})
end
+ processor.freeze
ProcessorExtension.new kind, processor
else
processor, config = resolve_args args, 2
# style 2: specified as Class or String class name
- if (processor_class = Extensions.resolve_class processor)
+ if (processor_class = Helpers.resolve_class processor)
unless processor_class < kind_class || (kind_java_class && processor_class < kind_java_class)
raise ::ArgumentError, %(Invalid type for #{kind_name} extension: #{processor})
end
processor_instance = processor_class.new config
processor_instance.freeze
@@ -1363,28 +1352,22 @@
extension
end
def add_syntax_processor kind, args, &block
kind_name = kind.to_s.tr '_', ' '
- kind_class_symbol = (kind_name.split.map {|it| it.capitalize }.push 'Processor').join.to_sym
- kind_class = Extensions.const_get kind_class_symbol
- kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol) : nil
+ kind_class_symbol = (kind_name.split.map {|it| it.capitalize } << 'Processor').join.to_sym
+ kind_class = Extensions.const_get kind_class_symbol, false
+ kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol, false) : nil
kind_store = instance_variable_get(%(@#{kind}_extensions).to_sym) || instance_variable_set(%(@#{kind}_extensions).to_sym, {})
# style 1: specified as block
if block_given?
name, config = resolve_args args, 2
- processor = kind_class.new as_symbol(name), config
- # NOTE class << processor idiom doesn't work in Opal
- #class << processor
- # include_dsl
- #end
- # NOTE kind_class.contants(false) doesn't exist in Ruby 1.8.7
- processor.extend kind_class.const_get :DSL if kind_class.constants.grep :DSL
- if block.arity == 1
- yield processor
- else
+ (processor = kind_class.new (as_symbol name), config).singleton_class.enable_dsl
+ if block.arity == 0
processor.instance_exec(&block)
+ else
+ yield processor
end
unless (name = as_symbol processor.name)
raise ::ArgumentError, %(No name specified for #{kind_name} extension at #{block.source_location})
end
unless processor.process_block_given?
@@ -1393,11 +1376,11 @@
processor.freeze
kind_store[name] = ProcessorExtension.new kind, processor
else
processor, name, config = resolve_args args, 3
# style 2: specified as Class or String class name
- if (processor_class = Extensions.resolve_class processor)
+ if (processor_class = Helpers.resolve_class processor)
unless processor_class < kind_class || (kind_java_class && processor_class < kind_java_class)
raise ::ArgumentError, %(Class specified for #{kind_name} extension does not inherit from #{kind_class}: #{processor})
end
processor_instance = processor_class.new as_symbol(name), config
unless (name = as_symbol processor_instance.name)
@@ -1451,17 +1434,15 @@
@groups ||= {}
end
def create name = nil, &block
if block_given?
- Registry.new({ (name || generate_name) => block })
+ Registry.new (name || generate_name) => block
else
Registry.new
end
end
- # Deprecated: Use create instead of build_registry
- alias build_registry create
# Public: Registers an extension Group that subsequently registers a
# collection of extensions.
#
# Registers the extension Group specified under the given name. If a name is
@@ -1499,11 +1480,11 @@
argc = args.size
if block_given?
resolved_group = block
elsif (group = args.pop)
# QUESTION should we instantiate the group class here or defer until activation??
- resolved_group = (resolve_class group) || group
+ resolved_group = (Helpers.resolve_class group) || group
else
raise ::ArgumentError, %(Extension group to register not specified)
end
name = args.pop || generate_name
unless args.empty?
@@ -1526,58 +1507,9 @@
#
# Returns nothing
def unregister *names
names.each {|group| @groups.delete group.to_sym }
nil
- end
-
- # Internal: Resolve the specified object as a Class
- #
- # object - The object to resolve as a Class
- #
- # Returns a Class if the specified object is a Class (but not a Module) or
- # a String that resolves to a Class; otherwise, nil
- def resolve_class object
- case object
- when ::Class
- object
- when ::String
- class_for_name object
- end
- end
-
- # Public: Resolves the Class object for the qualified name.
- #
- # Returns Class
- if ::RUBY_MIN_VERSION_2
- def class_for_name qualified_name
- resolved = ::Object.const_get qualified_name, false
- raise unless ::Class === resolved
- resolved
- rescue
- raise ::NameError, %(Could not resolve class for name: #{qualified_name})
- end
- elsif ::RUBY_MIN_VERSION_1_9
- def class_for_name qualified_name
- resolved = (qualified_name.split '::').reduce ::Object do |current, name|
- name.empty? ? current : (current.const_get name, false)
- end
- raise unless ::Class === resolved
- resolved
- rescue
- raise ::NameError, %(Could not resolve class for name: #{qualified_name})
- end
- else
- def class_for_name qualified_name
- resolved = (qualified_name.split '::').reduce ::Object do |current, name|
- # NOTE on Ruby 1.8, const_defined? only checks for constant in current scope
- name.empty? ? current : ((current.const_defined? name) ? (current.const_get name) : raise)
- end
- raise unless ::Class === resolved
- resolved
- rescue
- raise ::NameError, %(Could not resolve class for name: #{qualified_name})
- end
end
end
end
end