motion-kramdown 0.5.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 +7 -0
- data/README.md +84 -0
- data/lib/kramdown/compatibility.rb +36 -0
- data/lib/kramdown/converter/base.rb +259 -0
- data/lib/kramdown/converter/html.rb +461 -0
- data/lib/kramdown/converter/kramdown.rb +423 -0
- data/lib/kramdown/converter/latex.rb +600 -0
- data/lib/kramdown/converter/math_engine/itex2mml.rb +39 -0
- data/lib/kramdown/converter/math_engine/mathjax.rb +33 -0
- data/lib/kramdown/converter/math_engine/ritex.rb +38 -0
- data/lib/kramdown/converter/pdf.rb +624 -0
- data/lib/kramdown/converter/remove_html_tags.rb +53 -0
- data/lib/kramdown/converter/syntax_highlighter/coderay.rb +78 -0
- data/lib/kramdown/converter/syntax_highlighter/rouge.rb +37 -0
- data/lib/kramdown/converter/toc.rb +69 -0
- data/lib/kramdown/converter.rb +69 -0
- data/lib/kramdown/document.rb +144 -0
- data/lib/kramdown/element.rb +515 -0
- data/lib/kramdown/error.rb +17 -0
- data/lib/kramdown/options.rb +584 -0
- data/lib/kramdown/parser/base.rb +130 -0
- data/lib/kramdown/parser/gfm.rb +55 -0
- data/lib/kramdown/parser/html.rb +575 -0
- data/lib/kramdown/parser/kramdown/abbreviation.rb +67 -0
- data/lib/kramdown/parser/kramdown/autolink.rb +37 -0
- data/lib/kramdown/parser/kramdown/blank_line.rb +30 -0
- data/lib/kramdown/parser/kramdown/block_boundary.rb +33 -0
- data/lib/kramdown/parser/kramdown/blockquote.rb +39 -0
- data/lib/kramdown/parser/kramdown/codeblock.rb +56 -0
- data/lib/kramdown/parser/kramdown/codespan.rb +44 -0
- data/lib/kramdown/parser/kramdown/emphasis.rb +61 -0
- data/lib/kramdown/parser/kramdown/eob.rb +26 -0
- data/lib/kramdown/parser/kramdown/escaped_chars.rb +25 -0
- data/lib/kramdown/parser/kramdown/extensions.rb +201 -0
- data/lib/kramdown/parser/kramdown/footnote.rb +56 -0
- data/lib/kramdown/parser/kramdown/header.rb +59 -0
- data/lib/kramdown/parser/kramdown/horizontal_rule.rb +27 -0
- data/lib/kramdown/parser/kramdown/html.rb +160 -0
- data/lib/kramdown/parser/kramdown/html_entity.rb +33 -0
- data/lib/kramdown/parser/kramdown/line_break.rb +25 -0
- data/lib/kramdown/parser/kramdown/link.rb +139 -0
- data/lib/kramdown/parser/kramdown/list.rb +256 -0
- data/lib/kramdown/parser/kramdown/math.rb +54 -0
- data/lib/kramdown/parser/kramdown/paragraph.rb +54 -0
- data/lib/kramdown/parser/kramdown/smart_quotes.rb +174 -0
- data/lib/kramdown/parser/kramdown/table.rb +171 -0
- data/lib/kramdown/parser/kramdown/typographic_symbol.rb +44 -0
- data/lib/kramdown/parser/kramdown.rb +359 -0
- data/lib/kramdown/parser/markdown.rb +56 -0
- data/lib/kramdown/parser.rb +27 -0
- data/lib/kramdown/utils/configurable.rb +44 -0
- data/lib/kramdown/utils/entities.rb +347 -0
- data/lib/kramdown/utils/html.rb +75 -0
- data/lib/kramdown/utils/ordered_hash.rb +87 -0
- data/lib/kramdown/utils/string_scanner.rb +74 -0
- data/lib/kramdown/utils/unidecoder.rb +51 -0
- data/lib/kramdown/utils.rb +58 -0
- data/lib/kramdown/version.rb +15 -0
- data/lib/kramdown.rb +10 -0
- data/lib/motion-kramdown.rb +47 -0
- data/lib/rubymotion/encodings.rb +37 -0
- data/lib/rubymotion/rexml_shim.rb +25 -0
- data/lib/rubymotion/set.rb +1349 -0
- data/lib/rubymotion/version.rb +6 -0
- data/spec/document_tree.rb +48 -0
- data/spec/gfm_to_html.rb +95 -0
- data/spec/helpers/it_behaves_like.rb +27 -0
- data/spec/helpers/option_file.rb +46 -0
- data/spec/helpers/spec_options.rb +37 -0
- data/spec/helpers/tidy.rb +12 -0
- data/spec/html_to_html.rb +40 -0
- data/spec/html_to_kramdown_to_html.rb +46 -0
- data/spec/kramdown_to_xxx.rb +40 -0
- data/spec/test_location.rb +203 -0
- data/spec/test_string_scanner_kramdown.rb +19 -0
- data/spec/text_to_kramdown_to_html.rb +52 -0
- data/spec/text_to_latex.rb +33 -0
- metadata +164 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
module Kramdown::Converter::SyntaxHighlighter
|
11
|
+
|
12
|
+
# Uses Coderay to highlight code blocks and code spans.
|
13
|
+
module Coderay
|
14
|
+
|
15
|
+
begin
|
16
|
+
# RM require 'coderay'
|
17
|
+
|
18
|
+
# Highlighting via coderay is available if this constant is +true+.
|
19
|
+
# RM AVAILABLE = true
|
20
|
+
# RM rescue LoadError
|
21
|
+
AVAILABLE = false # :nodoc:
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.call(converter, text, lang, type, _unused_opts)
|
25
|
+
return nil unless converter.options[:enable_coderay]
|
26
|
+
|
27
|
+
if type == :span && lang
|
28
|
+
::CodeRay.scan(text, lang.to_sym).html(options(converter, :span)).chomp
|
29
|
+
elsif type == :block && (lang || options(converter, :default_lang))
|
30
|
+
lang = (lang || options(converter, :default_lang)).to_sym
|
31
|
+
::CodeRay.scan(text, lang).html(options(converter, :block)).chomp << "\n"
|
32
|
+
else
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.options(converter, type)
|
38
|
+
prepare_options(converter)
|
39
|
+
converter.data[:syntax_highlighter_coderay][type]
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.prepare_options(converter)
|
43
|
+
return if converter.data.key?(:syntax_highlighter_coderay)
|
44
|
+
|
45
|
+
cache = converter.data[:syntax_highlighter_coderay] = {}
|
46
|
+
|
47
|
+
opts = converter.options[:syntax_highlighter_opts].dup
|
48
|
+
span_opts = (opts.delete(:span) || {}).dup
|
49
|
+
block_opts = (opts.delete(:block) || {}).dup
|
50
|
+
[span_opts, block_opts].each do |hash|
|
51
|
+
hash.keys.each do |k|
|
52
|
+
hash[k.kind_of?(String) ? Kramdown::Options.str_to_sym(k) : k] = hash.delete(k)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
cache[:default_lang] = converter.options[:coderay_default_lang] || opts.delete(:default_lang)
|
57
|
+
cache[:span] = {
|
58
|
+
:css => converter.options[:coderay_css]
|
59
|
+
}.update(opts).update(span_opts).update(:wrap => :span)
|
60
|
+
cache[:block] = {
|
61
|
+
:wrap => converter.options[:coderay_wrap],
|
62
|
+
:line_numbers => converter.options[:coderay_line_numbers],
|
63
|
+
:line_number_start => converter.options[:coderay_line_number_start],
|
64
|
+
:tab_width => converter.options[:coderay_tab_width],
|
65
|
+
:bold_every => converter.options[:coderay_bold_every],
|
66
|
+
:css => converter.options[:coderay_css]
|
67
|
+
}.update(opts).update(block_opts)
|
68
|
+
|
69
|
+
[:css, :wrap, :line_numbers].each do |key|
|
70
|
+
[:block, :span].each do |type|
|
71
|
+
cache[type][key] = cache[type][key].to_sym if cache[type][key].kind_of?(String)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
module Kramdown::Converter::SyntaxHighlighter
|
11
|
+
|
12
|
+
# Uses Rouge which is CSS-compatible to Pygments to highlight code blocks and code spans.
|
13
|
+
module Rouge
|
14
|
+
|
15
|
+
begin
|
16
|
+
# RM require 'rouge'
|
17
|
+
|
18
|
+
# Highlighting via Rouge is available if this constant is +true+.
|
19
|
+
# RM AVAILABLE = true
|
20
|
+
# RM rescue LoadError, SyntaxError
|
21
|
+
AVAILABLE = false # :nodoc:
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.call(converter, text, lang, type, _unused_opts)
|
25
|
+
opts = converter.options[:syntax_highlighter_opts].dup
|
26
|
+
lexer = ::Rouge::Lexer.find_fancy(lang || opts[:default_lang], text)
|
27
|
+
return nil unless lexer
|
28
|
+
|
29
|
+
opts[:wrap] = false if type == :span
|
30
|
+
|
31
|
+
formatter = ::Rouge::Formatters::HTML.new(opts)
|
32
|
+
formatter.format(lexer.lex(text))
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
# RM require 'rexml/parsers/baseparser'
|
11
|
+
|
12
|
+
module Kramdown
|
13
|
+
|
14
|
+
module Converter
|
15
|
+
|
16
|
+
# Converts a Kramdown::Document to an element tree that represents the table of contents.
|
17
|
+
#
|
18
|
+
# The returned tree consists of Element objects of type :toc where the root element is just used
|
19
|
+
# as container object. Each :toc element contains as value the wrapped :header element and under
|
20
|
+
# the attribute key :id the header ID that should be used (note that this ID may not exist in
|
21
|
+
# the wrapped element).
|
22
|
+
#
|
23
|
+
# Since the TOC tree consists of special :toc elements, one cannot directly feed this tree to
|
24
|
+
# other converters!
|
25
|
+
class Toc < Base
|
26
|
+
|
27
|
+
def initialize(root, options)
|
28
|
+
super
|
29
|
+
@toc = Element.new(:toc)
|
30
|
+
@stack = []
|
31
|
+
@options[:template] = ''
|
32
|
+
end
|
33
|
+
|
34
|
+
def convert(el)
|
35
|
+
if el.type == :header && in_toc?(el)
|
36
|
+
attr = el.attr.dup
|
37
|
+
attr['id'] = generate_id(el.options[:raw_text]) if @options[:auto_ids] && !attr['id']
|
38
|
+
add_to_toc(el, attr['id']) if attr['id']
|
39
|
+
else
|
40
|
+
el.children.each {|child| convert(child)}
|
41
|
+
end
|
42
|
+
@toc
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def add_to_toc(el, id)
|
48
|
+
toc_element = Element.new(:toc, el, :id => id)
|
49
|
+
|
50
|
+
success = false
|
51
|
+
while !success
|
52
|
+
if @stack.empty?
|
53
|
+
@toc.children << toc_element
|
54
|
+
@stack << toc_element
|
55
|
+
success = true
|
56
|
+
elsif @stack.last.value.options[:level] < el.options[:level]
|
57
|
+
@stack.last.children << toc_element
|
58
|
+
@stack << toc_element
|
59
|
+
success = true
|
60
|
+
else
|
61
|
+
@stack.pop
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
# RM require 'kramdown/utils'
|
11
|
+
|
12
|
+
module Kramdown
|
13
|
+
|
14
|
+
# This module contains all available converters, i.e. classes that take a root Element and convert
|
15
|
+
# it to a specific output format. The result is normally a string. For example, the
|
16
|
+
# Converter::Html module converts an element tree into valid HTML.
|
17
|
+
#
|
18
|
+
# Converters use the Base class for common functionality (like applying a template to the output)
|
19
|
+
# \- see its API documentation for how to create a custom converter class.
|
20
|
+
module Converter
|
21
|
+
|
22
|
+
# RM autoload :Base, 'kramdown/converter/base'
|
23
|
+
# RM autoload :Html, 'kramdown/converter/html'
|
24
|
+
# RM autoload :Latex, 'kramdown/converter/latex'
|
25
|
+
# RM autoload :Kramdown, 'kramdown/converter/kramdown'
|
26
|
+
# RM autoload :Toc, 'kramdown/converter/toc'
|
27
|
+
# RM autoload :RemoveHtmlTags, 'kramdown/converter/remove_html_tags'
|
28
|
+
# RM autoload :Pdf, 'kramdown/converter/pdf'
|
29
|
+
|
30
|
+
extend ::Kramdown::Utils::Configurable
|
31
|
+
|
32
|
+
configurable(:syntax_highlighter)
|
33
|
+
|
34
|
+
# RM ["Coderay", "Rouge"].each do |klass_name|
|
35
|
+
# RM kn_down = klass_name.downcase.intern
|
36
|
+
# RM add_syntax_highlighter(kn_down) do |converter, text, lang, type, opts|
|
37
|
+
# RM require "kramdown/converter/syntax_highlighter/#{kn_down}"
|
38
|
+
# RM klass = ::Kramdown::Utils.deep_const_get("::Kramdown::Converter::SyntaxHighlighter::#{klass_name}")
|
39
|
+
# RM if klass::AVAILABLE
|
40
|
+
# RM add_syntax_highlighter(kn_down, klass)
|
41
|
+
# RM else
|
42
|
+
# RM add_syntax_highlighter(kn_down) {|*args| nil}
|
43
|
+
# RM end
|
44
|
+
# RM syntax_highlighter(kn_down).call(converter, text, lang, type, opts)
|
45
|
+
# RM end
|
46
|
+
# RM end
|
47
|
+
# RM
|
48
|
+
# RM configurable(:math_engine)
|
49
|
+
# RM
|
50
|
+
# RM require 'kramdown/converter/math_engine/mathjax'
|
51
|
+
# RM add_math_engine(:mathjax, ::Kramdown::Converter::MathEngine::Mathjax)
|
52
|
+
# RM
|
53
|
+
# RM ["Ritex", "Itex2MML"].each do |klass_name|
|
54
|
+
# RM kn_down = klass_name.downcase.intern
|
55
|
+
# RM add_math_engine(kn_down) do |converter, el, opts|
|
56
|
+
# RM require "kramdown/converter/math_engine/#{kn_down}"
|
57
|
+
# RM klass = ::Kramdown::Utils.deep_const_get("::Kramdown::Converter::MathEngine::#{klass_name}")
|
58
|
+
# RM if klass::AVAILABLE
|
59
|
+
# RM add_math_engine(kn_down, klass)
|
60
|
+
# RM else
|
61
|
+
# RM add_math_engine(kn_down) {|*args| nil}
|
62
|
+
# RM end
|
63
|
+
# RM math_engine(kn_down).call(converter, el, opts)
|
64
|
+
# RM end
|
65
|
+
# RM end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
# = kramdown
|
10
|
+
#
|
11
|
+
# kramdown is yet-another-markdown-parser but fast, pure Ruby, using a strict syntax definition and
|
12
|
+
# supporting several common extensions.
|
13
|
+
#
|
14
|
+
# The kramdown library is mainly written to support the kramdown-to-HTML conversion chain. However,
|
15
|
+
# due to its flexibility it supports other input and output formats as well. Here is a list of the
|
16
|
+
# supported formats:
|
17
|
+
#
|
18
|
+
# * input formats: kramdown (a Markdown superset), Markdown, HTML
|
19
|
+
# * output formats: HTML, kramdown, LaTeX (and therefore PDF)
|
20
|
+
#
|
21
|
+
# All the documentation on the available input and output formats is available at
|
22
|
+
# http://kramdown.gettalong.org.
|
23
|
+
#
|
24
|
+
# == Usage
|
25
|
+
#
|
26
|
+
# kramdown has a basic *Cloth API, so using kramdown is as easy as
|
27
|
+
#
|
28
|
+
# require 'kramdown'
|
29
|
+
#
|
30
|
+
# Kramdown::Document.new(text).to_html
|
31
|
+
#
|
32
|
+
# For detailed information have a look at the Kramdown::Document class.
|
33
|
+
#
|
34
|
+
# == License
|
35
|
+
#
|
36
|
+
# MIT - see the COPYING file.
|
37
|
+
|
38
|
+
|
39
|
+
# RM require 'kramdown/compatibility'
|
40
|
+
#
|
41
|
+
# RM require 'kramdown/version'
|
42
|
+
# RM require 'kramdown/element'
|
43
|
+
# RM require 'kramdown/error'
|
44
|
+
# RM require 'kramdown/parser'
|
45
|
+
# RM require 'kramdown/converter'
|
46
|
+
# RM require 'kramdown/options'
|
47
|
+
# RM require 'kramdown/utils'
|
48
|
+
|
49
|
+
module Kramdown
|
50
|
+
|
51
|
+
# Return the data directory for kramdown.
|
52
|
+
def self.data_dir
|
53
|
+
unless defined?(@@data_dir)
|
54
|
+
# RM require 'rbconfig'
|
55
|
+
@@data_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'kramdown'))
|
56
|
+
@@data_dir = File.expand_path(File.join(Config::CONFIG["datadir"], "kramdown")) if !File.exists?(@@data_dir)
|
57
|
+
raise "kramdown data directory not found! This is a bug, please report it!" unless File.directory?(@@data_dir)
|
58
|
+
end
|
59
|
+
@@data_dir
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
# The main interface to kramdown.
|
64
|
+
#
|
65
|
+
# This class provides a one-stop-shop for using kramdown to convert text into various output
|
66
|
+
# formats. Use it like this:
|
67
|
+
#
|
68
|
+
# require 'kramdown'
|
69
|
+
# doc = Kramdown::Document.new('This *is* some kramdown text')
|
70
|
+
# puts doc.to_html
|
71
|
+
#
|
72
|
+
# The #to_html method is a shortcut for using the Converter::Html class. See #method_missing for
|
73
|
+
# more information.
|
74
|
+
#
|
75
|
+
# The second argument to the ::new method is an options hash for customizing the behaviour of the
|
76
|
+
# used parser and the converter. See ::new for more information!
|
77
|
+
class Document
|
78
|
+
|
79
|
+
# The root Element of the element tree. It is immediately available after the ::new method has
|
80
|
+
# been called.
|
81
|
+
attr_accessor :root
|
82
|
+
|
83
|
+
# The options hash which holds the options for parsing/converting the Kramdown document.
|
84
|
+
attr_reader :options
|
85
|
+
|
86
|
+
# An array of warning messages. It is filled with warnings during the parsing phase (i.e. in
|
87
|
+
# ::new) and the conversion phase.
|
88
|
+
attr_reader :warnings
|
89
|
+
|
90
|
+
|
91
|
+
# Create a new Kramdown document from the string +source+ and use the provided +options+. The
|
92
|
+
# options that can be used are defined in the Options module.
|
93
|
+
#
|
94
|
+
# The special options key :input can be used to select the parser that should parse the
|
95
|
+
# +source+. It has to be the name of a class in the Kramdown::Parser module. For example, to
|
96
|
+
# select the kramdown parser, one would set the :input key to +Kramdown+. If this key is not
|
97
|
+
# set, it defaults to +Kramdown+.
|
98
|
+
#
|
99
|
+
# The +source+ is immediately parsed by the selected parser so that the root element is
|
100
|
+
# immediately available and the output can be generated.
|
101
|
+
def initialize(source, options = {})
|
102
|
+
@options = Options.merge(options).freeze
|
103
|
+
parser = (options[:input] || 'kramdown').to_s
|
104
|
+
parser = parser[0..0].upcase + parser[1..-1]
|
105
|
+
try_require('parser', parser)
|
106
|
+
if Parser.const_defined?(parser)
|
107
|
+
@root, @warnings = Parser.const_get(parser).parse(source, @options)
|
108
|
+
else
|
109
|
+
raise Kramdown::Error.new("kramdown has no parser to handle the specified input format: #{options[:input]}")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Check if a method is invoked that begins with +to_+ and if so, try to instantiate a converter
|
114
|
+
# class (i.e. a class in the Kramdown::Converter module) and use it for converting the document.
|
115
|
+
#
|
116
|
+
# For example, +to_html+ would instantiate the Kramdown::Converter::Html class.
|
117
|
+
def method_missing(id, *attr, &block)
|
118
|
+
if id.to_s =~ /^to_(\w+)$/ && (name = Utils.camelize($1)) &&
|
119
|
+
try_require('converter', name) && Converter.const_defined?(name)
|
120
|
+
output, warnings = Converter.const_get(name).convert(@root, @options)
|
121
|
+
@warnings.concat(warnings)
|
122
|
+
output
|
123
|
+
else
|
124
|
+
super
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def inspect #:nodoc:
|
129
|
+
"<KD:Document: options=#{@options.inspect} root=#{@root.inspect} warnings=#{@warnings.inspect}>"
|
130
|
+
end
|
131
|
+
|
132
|
+
# Try requiring a parser or converter class and don't raise an error if the file is not found.
|
133
|
+
def try_require(type, name)
|
134
|
+
# RM require("kramdown/#{type}/#{Utils.snake_case(name)}")
|
135
|
+
# RM true
|
136
|
+
# RM rescue LoadError
|
137
|
+
true
|
138
|
+
end
|
139
|
+
protected :try_require
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|