amp-front 0.1.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.
- data/.document +5 -0
- data/.gitignore +24 -0
- data/Ampfile +3 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +36 -0
- data/LICENSE +20 -0
- data/README.md +50 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/design_docs/commands.md +91 -0
- data/design_docs/dependencies.md +35 -0
- data/design_docs/plugins.md +47 -0
- data/features/amp.feature +8 -0
- data/features/amp_help.feature +36 -0
- data/features/amp_plugin_list.feature +10 -0
- data/features/step_definitions/amp-front_steps.rb +23 -0
- data/features/support/env.rb +4 -0
- data/lib/amp-front.rb +30 -0
- data/lib/amp-front/dispatch/commands/base.rb +158 -0
- data/lib/amp-front/dispatch/commands/builtin/help.rb +23 -0
- data/lib/amp-front/dispatch/commands/builtin/plugin.rb +24 -0
- data/lib/amp-front/dispatch/commands/validations.rb +171 -0
- data/lib/amp-front/dispatch/runner.rb +86 -0
- data/lib/amp-front/help/entries/__default__.erb +31 -0
- data/lib/amp-front/help/entries/ampfiles.md +42 -0
- data/lib/amp-front/help/entries/commands.erb +6 -0
- data/lib/amp-front/help/entries/new-commands.md +81 -0
- data/lib/amp-front/help/help.rb +312 -0
- data/lib/amp-front/plugins/base.rb +87 -0
- data/lib/amp-front/support/module_extensions.rb +92 -0
- data/lib/amp-front/third_party/maruku.rb +136 -0
- data/lib/amp-front/third_party/maruku/attributes.rb +227 -0
- data/lib/amp-front/third_party/maruku/defaults.rb +71 -0
- data/lib/amp-front/third_party/maruku/errors_management.rb +92 -0
- data/lib/amp-front/third_party/maruku/helpers.rb +260 -0
- data/lib/amp-front/third_party/maruku/input/charsource.rb +326 -0
- data/lib/amp-front/third_party/maruku/input/extensions.rb +69 -0
- data/lib/amp-front/third_party/maruku/input/html_helper.rb +189 -0
- data/lib/amp-front/third_party/maruku/input/linesource.rb +111 -0
- data/lib/amp-front/third_party/maruku/input/parse_block.rb +615 -0
- data/lib/amp-front/third_party/maruku/input/parse_doc.rb +234 -0
- data/lib/amp-front/third_party/maruku/input/parse_span_better.rb +746 -0
- data/lib/amp-front/third_party/maruku/input/rubypants.rb +225 -0
- data/lib/amp-front/third_party/maruku/input/type_detection.rb +147 -0
- data/lib/amp-front/third_party/maruku/input_textile2/t2_parser.rb +163 -0
- data/lib/amp-front/third_party/maruku/maruku.rb +33 -0
- data/lib/amp-front/third_party/maruku/output/to_ansi.rb +223 -0
- data/lib/amp-front/third_party/maruku/output/to_html.rb +991 -0
- data/lib/amp-front/third_party/maruku/output/to_markdown.rb +164 -0
- data/lib/amp-front/third_party/maruku/output/to_s.rb +56 -0
- data/lib/amp-front/third_party/maruku/string_utils.rb +191 -0
- data/lib/amp-front/third_party/maruku/structures.rb +167 -0
- data/lib/amp-front/third_party/maruku/structures_inspect.rb +87 -0
- data/lib/amp-front/third_party/maruku/structures_iterators.rb +61 -0
- data/lib/amp-front/third_party/maruku/textile2.rb +1 -0
- data/lib/amp-front/third_party/maruku/toc.rb +199 -0
- data/lib/amp-front/third_party/maruku/usage/example1.rb +33 -0
- data/lib/amp-front/third_party/maruku/version.rb +40 -0
- data/lib/amp-front/third_party/trollop.rb +766 -0
- data/spec/amp-front_spec.rb +25 -0
- data/spec/command_specs/base_spec.rb +123 -0
- data/spec/command_specs/command_spec.rb +97 -0
- data/spec/command_specs/help_spec.rb +33 -0
- data/spec/command_specs/spec_helper.rb +37 -0
- data/spec/command_specs/validations_spec.rb +267 -0
- data/spec/dispatch_specs/runner_spec.rb +116 -0
- data/spec/dispatch_specs/spec_helper.rb +15 -0
- data/spec/help_specs/help_entry_spec.rb +78 -0
- data/spec/help_specs/help_registry_spec.rb +77 -0
- data/spec/help_specs/spec_helper.rb +15 -0
- data/spec/plugin_specs/base_spec.rb +36 -0
- data/spec/plugin_specs/spec_helper.rb +15 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/support_specs/module_extensions_spec.rb +104 -0
- data/spec/support_specs/spec_helper.rb +15 -0
- data/test/third_party_tests/test_trollop.rb +1181 -0
- metadata +192 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
##################################################################
|
|
2
|
+
# Licensing Information #
|
|
3
|
+
# #
|
|
4
|
+
# The following code is licensed, as standalone code, under #
|
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
|
6
|
+
# #
|
|
7
|
+
# For information on the license of this code when distributed #
|
|
8
|
+
# with and used in conjunction with the other modules in the #
|
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
|
10
|
+
# #
|
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
|
12
|
+
# #
|
|
13
|
+
##################################################################
|
|
14
|
+
|
|
15
|
+
module Amp
|
|
16
|
+
module Plugins
|
|
17
|
+
class Base
|
|
18
|
+
extend ModuleExtensions
|
|
19
|
+
cattr_accessor :module, :author
|
|
20
|
+
cattr_accessor_with_default :loaded_plugins, []
|
|
21
|
+
|
|
22
|
+
# This tracks all subclasses (and subclasses of subclasses, etc). Plus, this
|
|
23
|
+
# method is inherited, so Wool::Plugins::Git.all_subclasses will have all
|
|
24
|
+
# subclasses of Wool::Plugins::Git!
|
|
25
|
+
def self.all_plugins
|
|
26
|
+
@all_plugins ||= [self]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# When a Plugin subclass is subclassed, store the subclass and inform the
|
|
30
|
+
# next superclass up the inheritance hierarchy.
|
|
31
|
+
def self.inherited(klass)
|
|
32
|
+
self.all_plugins << klass
|
|
33
|
+
next_klass = self.superclass
|
|
34
|
+
while next_klass != Amp::Plugins::Base.superclass
|
|
35
|
+
next_klass.send(:inherited, klass)
|
|
36
|
+
next_klass = next_klass.superclass
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Creates a Plugin subclass with the given name. Also allows specifying
|
|
41
|
+
# the superclass to use.
|
|
42
|
+
#
|
|
43
|
+
# Reopens existing plugins if they already exist, for user customization.
|
|
44
|
+
def self.create(name, superclass=Amp::Plugins::Base)
|
|
45
|
+
unless (name = name.to_s) && name.size > 0
|
|
46
|
+
raise ArgumentError.new('name must be a non-empty string')
|
|
47
|
+
end
|
|
48
|
+
name = name[0,1].upcase + name[1..-1]
|
|
49
|
+
klass = nil
|
|
50
|
+
Amp::Plugins.class_eval do
|
|
51
|
+
if const_defined?(name)
|
|
52
|
+
klass = const_get(name)
|
|
53
|
+
else
|
|
54
|
+
klass = Class.new(superclass)
|
|
55
|
+
const_set(name, klass) # So the class has a name
|
|
56
|
+
end
|
|
57
|
+
yield klass if block_given?
|
|
58
|
+
end
|
|
59
|
+
klass
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.load_rubygems_plugins
|
|
63
|
+
require 'rubygems'
|
|
64
|
+
files = Gem.find_files('amp_plugin.rb')
|
|
65
|
+
files.each do |file|
|
|
66
|
+
load file
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Generic initialization all plugins perform. Takes an options hash.
|
|
71
|
+
def initialize(opts={})
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def inspect
|
|
75
|
+
"#<Amp::Plugin::#{self.module} #{self.class.name} by #{self.class.author}>"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def module
|
|
79
|
+
self.class.module || self.class.name
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def load!
|
|
83
|
+
# Subclasses should implement this.
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
##################################################################
|
|
2
|
+
# Licensing Information #
|
|
3
|
+
# #
|
|
4
|
+
# The following code is licensed, as standalone code, under #
|
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
|
6
|
+
# #
|
|
7
|
+
# For information on the license of this code when distributed #
|
|
8
|
+
# with and used in conjunction with the other modules in the #
|
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
|
10
|
+
# #
|
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
|
12
|
+
# #
|
|
13
|
+
##################################################################
|
|
14
|
+
module Amp
|
|
15
|
+
# These are extensions to Amp modules. This module should be
|
|
16
|
+
# extended by any Amp modules seeking to take advantage of them.
|
|
17
|
+
# This prevents conflicts with other libraries defining extensions
|
|
18
|
+
# of the same name.
|
|
19
|
+
module ModuleExtensions
|
|
20
|
+
def singleton_class
|
|
21
|
+
class << self
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
end if RUBY_VERSION < "1.9"
|
|
25
|
+
|
|
26
|
+
# Creates a reader for the given instance variables on the class object.
|
|
27
|
+
def cattr_reader(*attrs)
|
|
28
|
+
attrs.each do |attr|
|
|
29
|
+
instance_eval("def #{attr}; @#{attr}; end")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Creates a writer for the given instance variables on the class object.
|
|
34
|
+
def cattr_writer(*attrs)
|
|
35
|
+
attrs.each do |attr|
|
|
36
|
+
instance_eval("def #{attr}=(val); @#{attr} = val; end")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Creates readers and writers for the given instance variables.
|
|
41
|
+
def cattr_accessor(*attrs)
|
|
42
|
+
cattr_reader(*attrs)
|
|
43
|
+
cattr_writer(*attrs)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def cattr_accessor_with_default(attr, default)
|
|
47
|
+
varname = "@#{attr}".to_sym
|
|
48
|
+
singleton_class.instance_eval do
|
|
49
|
+
define_method attr do
|
|
50
|
+
if instance_variable_defined?(varname)
|
|
51
|
+
instance_variable_get(varname)
|
|
52
|
+
else
|
|
53
|
+
instance_variable_set(varname, default)
|
|
54
|
+
default
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
cattr_writer(attr)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Creates a DSL-friendly set-and-getter method. The method, when called with
|
|
62
|
+
# no arguments, acts as a getter. When called with arguments, it acts as a
|
|
63
|
+
# setter. Uses class instance variables - this is not for generating
|
|
64
|
+
# instance methods.
|
|
65
|
+
#
|
|
66
|
+
# @example
|
|
67
|
+
# class A
|
|
68
|
+
# cattr_get_and_setter :type
|
|
69
|
+
# end
|
|
70
|
+
# class B < A
|
|
71
|
+
# type :silly
|
|
72
|
+
# end
|
|
73
|
+
# p B.type # => :silly
|
|
74
|
+
def cattr_get_and_setter(*attrs)
|
|
75
|
+
attrs.each do |attr|
|
|
76
|
+
cattr_accessor attr
|
|
77
|
+
singleton_class.instance_eval do
|
|
78
|
+
alias_method "#{attr}_old_get".to_sym, attr
|
|
79
|
+
define_method attr do |*args, &blk|
|
|
80
|
+
if args.size > 0
|
|
81
|
+
send("#{attr}=", *args)
|
|
82
|
+
elsif blk != nil
|
|
83
|
+
send("#{attr}=", blk)
|
|
84
|
+
else
|
|
85
|
+
send("#{attr}_old_get")
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (C) 2006 Andrea Censi <andrea (at) rubyforge.org>
|
|
3
|
+
#
|
|
4
|
+
# This file is part of Maruku.
|
|
5
|
+
#
|
|
6
|
+
# Maruku is free software; you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
|
8
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# Maruku is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# You should have received a copy of the GNU General Public License
|
|
17
|
+
# along with Maruku; if not, write to the Free Software
|
|
18
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
19
|
+
#++
|
|
20
|
+
|
|
21
|
+
require 'rexml/document'
|
|
22
|
+
|
|
23
|
+
dir_path = File.expand_path(File.dirname(__FILE__))
|
|
24
|
+
$:.unshift dir_path
|
|
25
|
+
|
|
26
|
+
# :include:MaRuKu.txt
|
|
27
|
+
module MaRuKu
|
|
28
|
+
|
|
29
|
+
module In
|
|
30
|
+
module Markdown
|
|
31
|
+
module SpanLevelParser; end
|
|
32
|
+
module BlockLevelParser; end
|
|
33
|
+
end
|
|
34
|
+
# more to come?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module Out
|
|
38
|
+
# Functions for exporting to MarkDown.
|
|
39
|
+
module Markdown; end
|
|
40
|
+
# Functions for exporting to HTML.
|
|
41
|
+
module HTML; end
|
|
42
|
+
# Functions for exporting to ANSI
|
|
43
|
+
module Ansi; end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# These are strings utilities.
|
|
47
|
+
module Strings; end
|
|
48
|
+
|
|
49
|
+
module Helpers; end
|
|
50
|
+
|
|
51
|
+
module Errors; end
|
|
52
|
+
|
|
53
|
+
class MDElement
|
|
54
|
+
include REXML
|
|
55
|
+
include MaRuKu
|
|
56
|
+
include Out::Markdown
|
|
57
|
+
include Out::HTML
|
|
58
|
+
include Out::Ansi
|
|
59
|
+
include Strings
|
|
60
|
+
include Helpers
|
|
61
|
+
include Errors
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class MDDocument < MDElement
|
|
66
|
+
include In::Markdown
|
|
67
|
+
include In::Markdown::SpanLevelParser
|
|
68
|
+
include In::Markdown::BlockLevelParser
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# This is the public interface
|
|
73
|
+
class Maruku < MaRuKu::MDDocument; end
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
require 'rexml/document'
|
|
78
|
+
|
|
79
|
+
# Structures definition
|
|
80
|
+
require 'maruku/structures'
|
|
81
|
+
require 'maruku/structures_inspect'
|
|
82
|
+
|
|
83
|
+
require 'maruku/defaults'
|
|
84
|
+
# Less typing
|
|
85
|
+
require 'maruku/helpers'
|
|
86
|
+
|
|
87
|
+
# Code for parsing whole Markdown documents
|
|
88
|
+
require 'maruku/input/parse_doc'
|
|
89
|
+
|
|
90
|
+
# Ugly things kept in a closet
|
|
91
|
+
require 'maruku/string_utils'
|
|
92
|
+
require 'maruku/input/linesource'
|
|
93
|
+
require 'maruku/input/type_detection'
|
|
94
|
+
|
|
95
|
+
# A class for reading and sanitizing inline HTML
|
|
96
|
+
require 'maruku/input/html_helper'
|
|
97
|
+
|
|
98
|
+
# Code for parsing Markdown block-level elements
|
|
99
|
+
require 'maruku/input/parse_block'
|
|
100
|
+
|
|
101
|
+
# Code for parsing Markdown span-level elements
|
|
102
|
+
require 'maruku/input/charsource'
|
|
103
|
+
require 'maruku/input/parse_span_better'
|
|
104
|
+
require 'maruku/input/rubypants'
|
|
105
|
+
|
|
106
|
+
require 'maruku/input/extensions'
|
|
107
|
+
|
|
108
|
+
require 'maruku/attributes'
|
|
109
|
+
|
|
110
|
+
require 'maruku/structures_iterators'
|
|
111
|
+
|
|
112
|
+
require 'maruku/errors_management'
|
|
113
|
+
|
|
114
|
+
# Code for creating a table of contents
|
|
115
|
+
require 'maruku/toc'
|
|
116
|
+
|
|
117
|
+
# Version and URL
|
|
118
|
+
require 'maruku/version'
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# Exporting to html
|
|
122
|
+
require 'maruku/output/to_html'
|
|
123
|
+
|
|
124
|
+
# Exporting to ansi terminal output
|
|
125
|
+
require 'maruku/output/to_ansi'
|
|
126
|
+
|
|
127
|
+
# Pretty print
|
|
128
|
+
require 'maruku/output/to_markdown'
|
|
129
|
+
|
|
130
|
+
# Exporting to text: strips all formatting (not complete)
|
|
131
|
+
require 'maruku/output/to_s'
|
|
132
|
+
|
|
133
|
+
# class Maruku is the global interface
|
|
134
|
+
require 'maruku/maruku'
|
|
135
|
+
|
|
136
|
+
$:.delete dir_path
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (C) 2006 Andrea Censi <andrea (at) rubyforge.org>
|
|
3
|
+
#
|
|
4
|
+
# This file is part of Maruku.
|
|
5
|
+
#
|
|
6
|
+
# Maruku is free software; you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
|
8
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# Maruku is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# You should have received a copy of the GNU General Public License
|
|
17
|
+
# along with Maruku; if not, write to the Free Software
|
|
18
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
19
|
+
#++
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class String
|
|
23
|
+
def quote_if_needed
|
|
24
|
+
if /[\s\'\"]/.match self
|
|
25
|
+
inspect
|
|
26
|
+
else
|
|
27
|
+
self
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module MaRuKu;
|
|
33
|
+
MagicChar = ':'
|
|
34
|
+
|
|
35
|
+
class AttributeList < Array
|
|
36
|
+
|
|
37
|
+
# An attribute list becomes
|
|
38
|
+
# {#id .cl key="val" ref}
|
|
39
|
+
# [ [:id, 'id'], [:class, 'id'], ['key', 'val'], [ :ref, 'ref' ]]
|
|
40
|
+
|
|
41
|
+
private :push
|
|
42
|
+
|
|
43
|
+
def push_key_val(key, val);
|
|
44
|
+
raise "Bad #{key.inspect}=#{val.inspect}" if not key and val
|
|
45
|
+
push [key, val]
|
|
46
|
+
end
|
|
47
|
+
def push_ref(ref_id);
|
|
48
|
+
|
|
49
|
+
raise "Bad :ref #{ref_id.inspect}" if not ref_id
|
|
50
|
+
push [:ref, ref_id+""]
|
|
51
|
+
|
|
52
|
+
# p "Now ", self ########################################
|
|
53
|
+
end
|
|
54
|
+
def push_class(val);
|
|
55
|
+
raise "Bad :id #{val.inspect}" if not val
|
|
56
|
+
push [:class, val]
|
|
57
|
+
end
|
|
58
|
+
def push_id(val);
|
|
59
|
+
raise "Bad :id #{val.inspect}" if not val
|
|
60
|
+
push [:id, val]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def to_s
|
|
64
|
+
map do |k,v|
|
|
65
|
+
case k
|
|
66
|
+
when :id; "#" + v.quote_if_needed
|
|
67
|
+
when :class; "." + v.quote_if_needed
|
|
68
|
+
when :ref; v.quote_if_needed
|
|
69
|
+
else k.quote_if_needed + "=" + v.quote_if_needed
|
|
70
|
+
end
|
|
71
|
+
end . join(' ')
|
|
72
|
+
end
|
|
73
|
+
alias to_md to_s
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
module MaRuKu; module In; module Markdown; module SpanLevelParser
|
|
79
|
+
|
|
80
|
+
def unit_tests_for_attribute_lists
|
|
81
|
+
[
|
|
82
|
+
[ "", [], "Empty lists are allowed" ],
|
|
83
|
+
[ "=", :throw, "Bad char to begin a list with." ],
|
|
84
|
+
[ "a =b", :throw, "No whitespace before `=`." ],
|
|
85
|
+
[ "a= b", :throw, "No whitespace after `=`." ],
|
|
86
|
+
|
|
87
|
+
[ "a b", [[:ref, 'a'],[:ref, 'b']], "More than one ref" ],
|
|
88
|
+
[ "a b c", [[:ref, 'a'],[:ref, 'b'],[:ref, 'c']], "More than one ref" ],
|
|
89
|
+
[ "hello notfound", [[:ref, 'hello'],[:ref, 'notfound']]],
|
|
90
|
+
|
|
91
|
+
[ "'a'", [[:ref, 'a']], "Quoted value." ],
|
|
92
|
+
[ '"a"' ],
|
|
93
|
+
|
|
94
|
+
[ "a=b", [['a','b']], "Simple key/val" ],
|
|
95
|
+
[ "'a'=b" ],
|
|
96
|
+
[ "'a'='b'" ],
|
|
97
|
+
[ "a='b'" ],
|
|
98
|
+
|
|
99
|
+
[ 'a="b\'"', [['a',"b\'"]], "Key/val with quotes" ],
|
|
100
|
+
[ 'a=b\''],
|
|
101
|
+
[ 'a="\\\'b\'"', [['a',"\'b\'"]], "Key/val with quotes" ],
|
|
102
|
+
|
|
103
|
+
['"', :throw, "Unclosed quotes"],
|
|
104
|
+
["'"],
|
|
105
|
+
["'a "],
|
|
106
|
+
['"a '],
|
|
107
|
+
|
|
108
|
+
[ "#a", [[:id, 'a']], "Simple ID" ],
|
|
109
|
+
[ "#'a'" ],
|
|
110
|
+
[ '#"a"' ],
|
|
111
|
+
|
|
112
|
+
[ "#", :throw, "Unfinished '#'." ],
|
|
113
|
+
[ ".", :throw, "Unfinished '.'." ],
|
|
114
|
+
[ "# a", :throw, "No white-space after '#'." ],
|
|
115
|
+
[ ". a", :throw, "No white-space after '.' ." ],
|
|
116
|
+
|
|
117
|
+
[ "a=b c=d", [['a','b'],['c','d']], "Tabbing" ],
|
|
118
|
+
[ " \ta=b \tc='d' "],
|
|
119
|
+
[ "\t a=b\t c='d'\t\t"],
|
|
120
|
+
|
|
121
|
+
[ ".\"a'", :throw, "Mixing quotes is bad." ],
|
|
122
|
+
|
|
123
|
+
].map { |s, expected, comment|
|
|
124
|
+
@expected = (expected ||= @expected)
|
|
125
|
+
@comment = (comment ||= (last=@comment) )
|
|
126
|
+
(comment == last && (comment += (@count+=1).to_s)) || @count = 1
|
|
127
|
+
expected = [md_ial(expected)] if expected.kind_of? Array
|
|
128
|
+
["{#{MagicChar}#{s}}", expected, "Attributes: #{comment}"]
|
|
129
|
+
}
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def md_al(s=[]); AttributeList.new(s) end
|
|
133
|
+
|
|
134
|
+
# returns nil or an AttributeList
|
|
135
|
+
def read_attribute_list(src, con, break_on_chars)
|
|
136
|
+
|
|
137
|
+
separators = break_on_chars + [?=,?\ ,?\t]
|
|
138
|
+
escaped = Maruku::EscapedCharInQuotes
|
|
139
|
+
|
|
140
|
+
al = AttributeList.new
|
|
141
|
+
while true
|
|
142
|
+
src.consume_whitespace
|
|
143
|
+
break if break_on_chars.include? src.cur_char
|
|
144
|
+
|
|
145
|
+
case src.cur_char
|
|
146
|
+
when nil
|
|
147
|
+
maruku_error "Attribute list terminated by EOF:\n "+
|
|
148
|
+
"#{al.inspect}" , src, con
|
|
149
|
+
tell_user "I try to continue and return partial attribute list:\n"+
|
|
150
|
+
al.inspect
|
|
151
|
+
break
|
|
152
|
+
when ?= # error
|
|
153
|
+
maruku_error "In attribute lists, cannot start identifier with `=`."
|
|
154
|
+
tell_user "I try to continue"
|
|
155
|
+
src.ignore_char
|
|
156
|
+
when ?# # id definition
|
|
157
|
+
src.ignore_char
|
|
158
|
+
if id = read_quoted_or_unquoted(src, con, escaped, separators)
|
|
159
|
+
al.push_id id
|
|
160
|
+
else
|
|
161
|
+
maruku_error 'Could not read `id` attribute.', src, con
|
|
162
|
+
tell_user 'Trying to ignore bad `id` attribute.'
|
|
163
|
+
end
|
|
164
|
+
when ?. # class definition
|
|
165
|
+
src.ignore_char
|
|
166
|
+
if klass = read_quoted_or_unquoted(src, con, escaped, separators)
|
|
167
|
+
al.push_class klass
|
|
168
|
+
else
|
|
169
|
+
maruku_error 'Could not read `class` attribute.', src, con
|
|
170
|
+
tell_user 'Trying to ignore bad `class` attribute.'
|
|
171
|
+
end
|
|
172
|
+
else
|
|
173
|
+
if key = read_quoted_or_unquoted(src, con, escaped, separators)
|
|
174
|
+
if src.cur_char == ?=
|
|
175
|
+
src.ignore_char # skip the =
|
|
176
|
+
if val = read_quoted_or_unquoted(src, con, escaped, separators)
|
|
177
|
+
al.push_key_val(key, val)
|
|
178
|
+
else
|
|
179
|
+
maruku_error "Could not read value for key #{key.inspect}.",
|
|
180
|
+
src, con
|
|
181
|
+
tell_user "Ignoring key #{key.inspect}."
|
|
182
|
+
end
|
|
183
|
+
else
|
|
184
|
+
al.push_ref key
|
|
185
|
+
end
|
|
186
|
+
else
|
|
187
|
+
maruku_error 'Could not read key or reference.'
|
|
188
|
+
end
|
|
189
|
+
end # case
|
|
190
|
+
end # while true
|
|
191
|
+
al
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# We need a helper
|
|
196
|
+
def is_ial(e); e.kind_of? MDElement and e.node_type == :ial end
|
|
197
|
+
|
|
198
|
+
def merge_ial(elements, src, con)
|
|
199
|
+
|
|
200
|
+
# Apply each IAL to the element before
|
|
201
|
+
elements.each_with_index do |e, i|
|
|
202
|
+
if is_ial(e) && i>= 1 then
|
|
203
|
+
before = elements[i-1]
|
|
204
|
+
after = elements[i+1]
|
|
205
|
+
if before.kind_of? MDElement
|
|
206
|
+
before.al = e.ial
|
|
207
|
+
elsif after.kind_of? MDElement
|
|
208
|
+
after.al = e.ial
|
|
209
|
+
else
|
|
210
|
+
maruku_error "It is not clear to me what element this IAL {:#{e.ial.to_md}} \n"+
|
|
211
|
+
"is referring to. The element before is a #{before.class.to_s}, \n"+
|
|
212
|
+
"the element after is a #{after.class.to_s}.\n"+
|
|
213
|
+
"\n before: #{before.inspect}"+
|
|
214
|
+
"\n after: #{after.inspect}",
|
|
215
|
+
src, con
|
|
216
|
+
# xxx dire se c'è empty vicino
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
if not Globals[:debug_keep_ials]
|
|
222
|
+
elements.delete_if {|x| is_ial(x) unless x == elements.first}
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
end end end end
|
|
227
|
+
#module MaRuKu; module In; module Markdown; module SpanLevelParser
|