gloo-md 1.4 → 1.5
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 +4 -4
- data/lib/markdown_ext.rb +19 -8
- data/lib/md.rb +15 -7
- data/lib/md_doc.rb +150 -34
- metadata +69 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a096b22407ded192c923fe7a248739abdf91312dfb7c3adbb07971b8d521a8ab
|
|
4
|
+
data.tar.gz: c9e5db96603db5998f7f5d99c028760ea5d457e8efd531c5cea126491595a3e8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 95def51afd4d575cb46bca609e233f8916c94cd40f4811751638b37b6661c9f2c8d84a902c76b64369259d477a57ee7683c0f5f34cbb33f2e8c4cbd03c660b71
|
|
7
|
+
data.tar.gz: c65726498e76d43dac867a9da4f6f47290e819d873be64eee01b2481d5519439c406d709a43595cc17f4e2c97c03133c8e972b337becfc60563a8f486a569f73
|
data/lib/markdown_ext.rb
CHANGED
|
@@ -26,20 +26,27 @@ class MarkdownExt
|
|
|
26
26
|
|
|
27
27
|
#
|
|
28
28
|
# Render gloo markdown extensions.
|
|
29
|
+
# A block runs from its [!...] line to the next blank line, the next
|
|
30
|
+
# block, or the end of the data. The engine, when given, is used to
|
|
31
|
+
# warn about an unknown extension.
|
|
29
32
|
#
|
|
30
|
-
def self.render_extensions data
|
|
33
|
+
def self.render_extensions( data, engine = nil )
|
|
31
34
|
return '' if data.nil?
|
|
32
35
|
|
|
33
36
|
out_data = ""
|
|
34
37
|
one_ext = ""
|
|
35
38
|
in_ext = false
|
|
36
39
|
data.lines.each_with_index do |line, index|
|
|
37
|
-
|
|
40
|
+
# A line starting [![ is a Markdown image link (eg. a badge), not a block.
|
|
41
|
+
if line.start_with?( '[!' ) && !line.start_with?( '[![' )
|
|
42
|
+
# A new block finishes any block still open; a blank line keeps
|
|
43
|
+
# the two apart for the Markdown renderer.
|
|
44
|
+
out_data << render_one_ext( one_ext, engine ) << "\n" if in_ext
|
|
38
45
|
in_ext = true
|
|
39
|
-
one_ext = line
|
|
46
|
+
one_ext = line.dup
|
|
40
47
|
elsif in_ext && line.strip.blank?
|
|
41
48
|
in_ext = false
|
|
42
|
-
out_data << render_one_ext( one_ext )
|
|
49
|
+
out_data << render_one_ext( one_ext, engine )
|
|
43
50
|
out_data << line
|
|
44
51
|
elsif in_ext
|
|
45
52
|
one_ext << line
|
|
@@ -48,6 +55,9 @@ class MarkdownExt
|
|
|
48
55
|
end
|
|
49
56
|
end
|
|
50
57
|
|
|
58
|
+
# A block at the very end has no blank line after it.
|
|
59
|
+
out_data << render_one_ext( one_ext, engine ) if in_ext
|
|
60
|
+
|
|
51
61
|
return out_data
|
|
52
62
|
end
|
|
53
63
|
|
|
@@ -58,7 +68,7 @@ class MarkdownExt
|
|
|
58
68
|
#
|
|
59
69
|
# Render one markdown extension.
|
|
60
70
|
#
|
|
61
|
-
def self.render_one_ext( data )
|
|
71
|
+
def self.render_one_ext( data, engine = nil )
|
|
62
72
|
if data.start_with?( PANEL )
|
|
63
73
|
return render_panel( data )
|
|
64
74
|
elsif data.start_with?( QUOTE )
|
|
@@ -72,9 +82,10 @@ class MarkdownExt
|
|
|
72
82
|
elsif data.start_with?( IDEA )
|
|
73
83
|
return render_idea( data )
|
|
74
84
|
else
|
|
75
|
-
#
|
|
76
|
-
|
|
77
|
-
|
|
85
|
+
# Keep the block as plain text so its content isn't lost.
|
|
86
|
+
tag = data.lines.first.to_s[ /\A\[![^\]]*\]?/ ]
|
|
87
|
+
engine&.warn "Unknown markdown extension '#{tag}'; it was shown as plain text."
|
|
88
|
+
return data
|
|
78
89
|
end
|
|
79
90
|
end
|
|
80
91
|
|
data/lib/md.rb
CHANGED
|
@@ -67,21 +67,26 @@ class Md < Gloo::Core::Obj
|
|
|
67
67
|
|
|
68
68
|
#
|
|
69
69
|
# Render the markdown as HTML.
|
|
70
|
-
#
|
|
71
|
-
#
|
|
70
|
+
# With an optional destination, the HTML goes there and it is true
|
|
71
|
+
# (false if the destination doesn't exist). With none, the HTML is
|
|
72
|
+
# put in it.
|
|
72
73
|
#
|
|
73
74
|
def msg_render
|
|
74
|
-
html = MarkdownExt.render_extensions( value )
|
|
75
|
+
html = MarkdownExt.render_extensions( value, @engine )
|
|
75
76
|
html = Md.md_2_html( html )
|
|
76
77
|
|
|
77
|
-
# Put the HTML in the optional parameter if one is given.
|
|
78
78
|
if @params&.token_count&.positive?
|
|
79
79
|
pn = Gloo::Core::Pn.new( @engine, @params.first )
|
|
80
80
|
o = pn.resolve
|
|
81
|
+
unless o
|
|
82
|
+
@engine.err Gloo::Core::NotFound.object( @params.first )
|
|
83
|
+
return @engine.heap.it.set_to( false )
|
|
84
|
+
end
|
|
85
|
+
|
|
81
86
|
o.set_value html
|
|
87
|
+
return @engine.heap.it.set_to( true )
|
|
82
88
|
end
|
|
83
89
|
|
|
84
|
-
# Put the HTML in it, in any case.
|
|
85
90
|
@engine.heap.it.set_to html
|
|
86
91
|
end
|
|
87
92
|
|
|
@@ -140,10 +145,13 @@ class Md < Gloo::Core::Obj
|
|
|
140
145
|
:shortcut => KEYWORD_SHORT,
|
|
141
146
|
:description => 'Markdown data in a text string. Also supports ' \
|
|
142
147
|
'gloo Markdown extensions (panel, note, quote, idea and check ' \
|
|
143
|
-
'blocks) rendered via MarkdownExt when the data is rendered.'
|
|
148
|
+
'blocks) rendered via MarkdownExt when the data is rendered. ' \
|
|
149
|
+
'A block runs from its [!...] line to the next blank line, the ' \
|
|
150
|
+
'next block, or the end of the text. An unknown extension is ' \
|
|
151
|
+
'kept as plain text, with a warning.',
|
|
144
152
|
:messages => [
|
|
145
153
|
'show — Show the markdown data in the terminal.',
|
|
146
|
-
'render ({dst}) — Convert the markdown to HTML
|
|
154
|
+
'render ({dst}) — Convert the markdown to HTML. With {dst}, the HTML is put in the {dst} object and it is true (a {dst} that does not exist is an error, and it is false). With no {dst}, the HTML is put in it.',
|
|
147
155
|
'update_asset_path — Update asset paths for all images in the source markdown, so files can refer to images from a path different from the page using them.'
|
|
148
156
|
],
|
|
149
157
|
:examples => <<~EXAMPLES.strip
|
data/lib/md_doc.rb
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
# children and the Markdown body as a text child.
|
|
7
7
|
#
|
|
8
8
|
require 'yaml'
|
|
9
|
+
require 'date'
|
|
9
10
|
|
|
10
11
|
class MdDoc < Gloo::Core::Obj
|
|
11
12
|
|
|
@@ -79,66 +80,75 @@ class MdDoc < Gloo::Core::Obj
|
|
|
79
80
|
|
|
80
81
|
#
|
|
81
82
|
# Read the file at path, parse frontmatter and body, populate children.
|
|
82
|
-
# Only scalar frontmatter values
|
|
83
|
-
# (arrays, nested hashes) are skipped —
|
|
84
|
-
# re-reading the file.
|
|
83
|
+
# Only scalar frontmatter values (including dates and times) become gloo
|
|
84
|
+
# string children; complex values (arrays, nested hashes) are skipped —
|
|
85
|
+
# they are preserved on write by re-reading the file.
|
|
86
|
+
# It is true when the file was read, false if it couldn't be.
|
|
85
87
|
#
|
|
86
88
|
def msg_read
|
|
87
89
|
path = resolve_path
|
|
88
|
-
return unless path
|
|
90
|
+
return @engine.heap.it.set_to( false ) unless path
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return
|
|
93
|
-
end
|
|
92
|
+
content = read_file( path )
|
|
93
|
+
return @engine.heap.it.set_to( false ) unless content
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
fm_hash, body_text = parse_frontmatter( content, path )
|
|
96
|
+
return @engine.heap.it.set_to( false ) unless fm_hash
|
|
97
97
|
|
|
98
98
|
fm_can = find_child FRONTMATTER
|
|
99
|
-
|
|
99
|
+
# Start from the file's keys only, not ones left from an earlier read.
|
|
100
|
+
fm_can&.delete_children
|
|
101
|
+
if fm_can
|
|
100
102
|
fm_hash.each do |key, val|
|
|
101
103
|
next unless scalar?( val )
|
|
102
104
|
child = fm_can.find_add_child( key.to_s, 'string' )
|
|
103
|
-
child.set_value val
|
|
105
|
+
child.set_value scalar_text( val )
|
|
104
106
|
end
|
|
105
107
|
end
|
|
106
108
|
|
|
107
109
|
body = find_child BODY
|
|
108
110
|
body.set_value( body_text ) if body
|
|
111
|
+
@engine.heap.it.set_to true
|
|
109
112
|
end
|
|
110
113
|
|
|
111
114
|
#
|
|
112
115
|
# Serialize frontmatter and body children back to the file at path.
|
|
113
116
|
# Re-reads the current file to get the base hash (preserving arrays and other
|
|
114
|
-
# complex values), then overlays the scalar children
|
|
115
|
-
#
|
|
117
|
+
# complex values), then overlays the scalar children that were changed.
|
|
118
|
+
# Creates the file if it does not exist.
|
|
116
119
|
#
|
|
117
120
|
def msg_write
|
|
118
121
|
path = resolve_path
|
|
119
122
|
return unless path
|
|
120
123
|
|
|
121
|
-
expanded = File.expand_path( path )
|
|
122
|
-
|
|
123
124
|
# Re-read the file so arrays and nested hashes survive unchanged.
|
|
124
125
|
base = {}
|
|
125
|
-
if File.exist?(
|
|
126
|
-
|
|
126
|
+
if File.exist?( path )
|
|
127
|
+
content = read_file( path )
|
|
128
|
+
return unless content
|
|
129
|
+
|
|
130
|
+
base, _ = parse_frontmatter( content, path )
|
|
131
|
+
# Invalid frontmatter was reported; don't overwrite the file.
|
|
132
|
+
return unless base
|
|
127
133
|
end
|
|
128
134
|
|
|
129
135
|
fm_can = find_child FRONTMATTER
|
|
130
136
|
|
|
131
|
-
# Overlay
|
|
137
|
+
# Overlay changed children; updating an existing key preserves its
|
|
138
|
+
# position, and an unchanged one keeps its YAML type (eg. a date).
|
|
139
|
+
# A changed one keeps its type too when its new text fits it.
|
|
132
140
|
if fm_can
|
|
133
141
|
fm_can.children.each do |child|
|
|
134
|
-
base[ child.name ]
|
|
142
|
+
next if base.key?( child.name ) && scalar_text( base[ child.name ] ) == child.value.to_s
|
|
143
|
+
|
|
144
|
+
base[ child.name ] = typed_value( base[ child.name ], child.value )
|
|
135
145
|
end
|
|
136
146
|
end
|
|
137
147
|
|
|
138
148
|
body = find_child BODY
|
|
139
149
|
body_text = body ? body.value.to_s : ''
|
|
140
150
|
|
|
141
|
-
File.write(
|
|
151
|
+
file_op( 'write', path ) { File.write( path, build_content( base, body_text ) ) }
|
|
142
152
|
end
|
|
143
153
|
|
|
144
154
|
|
|
@@ -154,33 +164,129 @@ class MdDoc < Gloo::Core::Obj
|
|
|
154
164
|
#
|
|
155
165
|
def scalar?( val )
|
|
156
166
|
val.is_a?( String ) || val.is_a?( Integer ) || val.is_a?( Float ) ||
|
|
157
|
-
val.is_a?( TrueClass ) || val.is_a?( FalseClass ) || val.nil?
|
|
167
|
+
val.is_a?( TrueClass ) || val.is_a?( FalseClass ) || val.nil? ||
|
|
168
|
+
val.is_a?( Date ) || val.is_a?( Time )
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
#
|
|
172
|
+
# The text for a scalar frontmatter value, as its string child holds it.
|
|
173
|
+
# YAML reads a time with no zone as UTC, so times are shown in UTC
|
|
174
|
+
# (eg. 2026-10-01 09:30:00 UTC) rather than converted to local time.
|
|
175
|
+
#
|
|
176
|
+
def scalar_text( val )
|
|
177
|
+
return val.utc.strftime( '%Y-%m-%d %H:%M:%S UTC' ) if val.is_a?( Time )
|
|
178
|
+
|
|
179
|
+
return val.to_s
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
#
|
|
183
|
+
# The kind of a frontmatter value whose type write keeps: :boolean,
|
|
184
|
+
# :number, :date or :time. Nil for text and anything else.
|
|
185
|
+
#
|
|
186
|
+
def value_kind( val )
|
|
187
|
+
case val
|
|
188
|
+
when TrueClass, FalseClass then :boolean
|
|
189
|
+
when Integer, Float then :number
|
|
190
|
+
when Time then :time
|
|
191
|
+
when Date then :date
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
#
|
|
196
|
+
# The value to write for a changed child. If the old value was a
|
|
197
|
+
# boolean, number, date or time, and the new text reads as the same
|
|
198
|
+
# kind of value (and back as the same text), write it as that kind;
|
|
199
|
+
# otherwise write the text as a string.
|
|
200
|
+
#
|
|
201
|
+
def typed_value( old, text )
|
|
202
|
+
kind = value_kind( old )
|
|
203
|
+
return text unless kind
|
|
204
|
+
|
|
205
|
+
# Read shows times with a UTC suffix, which YAML spells Z.
|
|
206
|
+
parsed = YAML.safe_load( text.to_s.sub( / UTC\z/, ' Z' ), permitted_classes: [ Date, Time ] )
|
|
207
|
+
return text unless value_kind( parsed ) == kind
|
|
208
|
+
# Text that YAML would trim or reinterpret (eg. '3 # note') stays text.
|
|
209
|
+
return text unless without_zone( scalar_text( parsed ) ) == without_zone( text.to_s )
|
|
210
|
+
|
|
211
|
+
return parsed
|
|
212
|
+
rescue Psych::Exception
|
|
213
|
+
return text
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
#
|
|
217
|
+
# A time's text without a trailing UTC or Z zone, for comparing.
|
|
218
|
+
#
|
|
219
|
+
def without_zone( text )
|
|
220
|
+
return text.sub( / (UTC|Z)\z/, '' )
|
|
158
221
|
end
|
|
159
222
|
|
|
160
223
|
#
|
|
161
224
|
# Get the expanded path string from the path child.
|
|
225
|
+
# Reports an error and returns nil if there's no path.
|
|
162
226
|
#
|
|
163
227
|
def resolve_path
|
|
164
228
|
o = find_child PATH
|
|
165
|
-
|
|
166
|
-
|
|
229
|
+
if o.nil? || o.value.to_s.strip.empty?
|
|
230
|
+
@engine.err "md_doc '#{name}' has no path; put a file path into #{name}.path first."
|
|
231
|
+
return nil
|
|
232
|
+
end
|
|
167
233
|
|
|
168
234
|
File.expand_path( o.value.to_s )
|
|
169
235
|
end
|
|
170
236
|
|
|
237
|
+
#
|
|
238
|
+
# Read the file at path. Reports an error and returns nil if it's
|
|
239
|
+
# missing or can't be read.
|
|
240
|
+
#
|
|
241
|
+
def read_file( path )
|
|
242
|
+
unless File.exist?( path )
|
|
243
|
+
@engine.err Gloo::Core::NotFound.file( path )
|
|
244
|
+
return nil
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
return file_op( 'read', path ) { File.read( path ) }
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
#
|
|
251
|
+
# Run a file operation, reporting a failure (eg. no permission, a
|
|
252
|
+
# missing folder) as an error. Returns nil if it failed.
|
|
253
|
+
#
|
|
254
|
+
def file_op( action, path )
|
|
255
|
+
return yield
|
|
256
|
+
rescue SystemCallError => e
|
|
257
|
+
@engine.err "Could not #{action} '#{path}': #{e.message}"
|
|
258
|
+
return nil
|
|
259
|
+
end
|
|
260
|
+
|
|
171
261
|
#
|
|
172
262
|
# Parse YAML frontmatter from file content.
|
|
173
263
|
# Returns [fm_hash, body_text]. If there is no frontmatter block,
|
|
174
264
|
# fm_hash is empty and body_text is the full content.
|
|
265
|
+
# Dates and times are allowed. Invalid YAML is reported as an error,
|
|
266
|
+
# and fm_hash is nil.
|
|
175
267
|
#
|
|
176
|
-
def parse_frontmatter( content )
|
|
268
|
+
def parse_frontmatter( content, path )
|
|
177
269
|
if content =~ /\A---\s*\n(.*?\n)---\s*\n?(.*)\z/m
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return fm_hash, body_text
|
|
270
|
+
fm_text, body_text = $1, $2
|
|
271
|
+
fm_hash = YAML.safe_load( fm_text, permitted_classes: [ Date, Time ] ) || {}
|
|
272
|
+
return fm_hash, body_text if fm_hash.is_a?( Hash )
|
|
273
|
+
|
|
274
|
+
return frontmatter_err( path, "it isn't a list of key: value pairs" )
|
|
181
275
|
end
|
|
182
276
|
|
|
183
277
|
return {}, content
|
|
278
|
+
rescue Psych::SyntaxError => e
|
|
279
|
+
return frontmatter_err( path, "it isn't valid YAML (#{e.problem})" )
|
|
280
|
+
rescue Psych::Exception => e
|
|
281
|
+
return frontmatter_err( path, "it couldn't be loaded (#{e.message})" )
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
#
|
|
285
|
+
# Report frontmatter that can't be used, and return no hash or body.
|
|
286
|
+
#
|
|
287
|
+
def frontmatter_err( path, reason )
|
|
288
|
+
@engine.err "Couldn't read the frontmatter in '#{path}': #{reason}."
|
|
289
|
+
return nil, nil
|
|
184
290
|
end
|
|
185
291
|
|
|
186
292
|
#
|
|
@@ -192,8 +298,15 @@ class MdDoc < Gloo::Core::Obj
|
|
|
192
298
|
return body_text
|
|
193
299
|
end
|
|
194
300
|
|
|
301
|
+
# Write times in UTC, as they were most likely written, not local time.
|
|
302
|
+
fm_hash = fm_hash.transform_values { |v| v.is_a?( Time ) ? v.utc : v }
|
|
303
|
+
|
|
195
304
|
# to_yaml emits "---\nkey: val\n"; strip the leading "---\n" and rewrap.
|
|
196
305
|
fm_yaml = fm_hash.to_yaml.sub( /\A---\n/, '' )
|
|
306
|
+
|
|
307
|
+
# to_yaml writes a UTC time as 2026-10-01 09:30:00.000000000 Z. A time
|
|
308
|
+
# with no zone reads as UTC, so dropping the suffix keeps the same time.
|
|
309
|
+
fm_yaml = fm_yaml.gsub( /(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d)\.0+ Z$/, '\1' )
|
|
197
310
|
"---\n#{fm_yaml}---\n#{body_text}"
|
|
198
311
|
end
|
|
199
312
|
|
|
@@ -220,15 +333,18 @@ class MdDoc < Gloo::Core::Obj
|
|
|
220
333
|
'body (text) — The Markdown body (everything after the --- closing delimiter).'
|
|
221
334
|
],
|
|
222
335
|
:messages => [
|
|
223
|
-
'read — Read the file at path, parse the YAML frontmatter and Markdown body.
|
|
224
|
-
'write — Serialize frontmatter children back to YAML and combine with body. Writes the result to the file at path, creating it if it does not exist. Key order is preserved
|
|
336
|
+
'read — Read the file at path, parse the YAML frontmatter and Markdown body. The frontmatter children are replaced with exactly the keys in the file (keys from an earlier read are removed); dates and times become text (times in UTC). Populates frontmatter.* children and body. It is true when the file was read, false if it could not be.',
|
|
337
|
+
'write — Serialize frontmatter children back to YAML and combine with body. Writes the result to the file at path, creating it if it does not exist. Key order is preserved. A value keeps its YAML type (a date, time, number or true/false): unchanged values always, and changed values when the new text is that type too (eg. 2026-10-05 for a date); otherwise the new text is written as text.'
|
|
225
338
|
],
|
|
226
339
|
:notes => 'If the file has no frontmatter block, frontmatter ' \
|
|
227
340
|
'will have no children and body will contain the full file ' \
|
|
228
|
-
'content.
|
|
229
|
-
'
|
|
230
|
-
|
|
231
|
-
'
|
|
341
|
+
'content. These are errors, and read leaves the children as ' \
|
|
342
|
+
'they were and puts false in it: an empty path, a file that ' \
|
|
343
|
+
'does not exist or cannot be read, and frontmatter that is not ' \
|
|
344
|
+
'valid YAML. An empty path or a failed write is also an error ' \
|
|
345
|
+
'for write; write does not overwrite a file whose frontmatter ' \
|
|
346
|
+
"is not valid YAML. Uses Ruby's built-in psych library for " \
|
|
347
|
+
'YAML parsing — no additional dependencies.',
|
|
232
348
|
:examples => <<~EXAMPLES.strip
|
|
233
349
|
doc [md_doc] :
|
|
234
350
|
path [file] : ~/notes/project.md
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gloo-md
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.5'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Eric Crane
|
|
@@ -23,6 +23,74 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: 3.6.0
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: gloo
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '7.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '7.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: bundler
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: minitest
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '5.1'
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: 5.14.2
|
|
64
|
+
type: :development
|
|
65
|
+
prerelease: false
|
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
67
|
+
requirements:
|
|
68
|
+
- - "~>"
|
|
69
|
+
- !ruby/object:Gem::Version
|
|
70
|
+
version: '5.1'
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: 5.14.2
|
|
74
|
+
- !ruby/object:Gem::Dependency
|
|
75
|
+
name: rake
|
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - "~>"
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: '13.0'
|
|
81
|
+
- - ">="
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: 13.0.1
|
|
84
|
+
type: :development
|
|
85
|
+
prerelease: false
|
|
86
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - "~>"
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
version: '13.0'
|
|
91
|
+
- - ">="
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: 13.0.1
|
|
26
94
|
description: Adds Markdown support to Gloo.
|
|
27
95
|
email:
|
|
28
96
|
- eric.crane@mac.com
|