mint 0.5.1 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/Gemfile +18 -0
  2. data/README.md +3 -3
  3. data/bin/mint +27 -27
  4. data/bin/mint-epub +6 -6
  5. data/config/syntax.yaml +12 -12
  6. data/{templates → config/templates}/base/style.sass +11 -4
  7. data/config/templates/default/css/style.css +158 -0
  8. data/config/templates/default/layout.haml +8 -0
  9. data/{templates → config/templates}/default/style.sass +0 -0
  10. data/{templates/default → config/templates/protocol}/layout.haml +0 -0
  11. data/config/templates/protocol/style.sass +20 -0
  12. data/config/templates/reset.css +92 -0
  13. data/config/templates/zen/css/style.css +145 -0
  14. data/{templates/pro → config/templates/zen}/layout.haml +0 -0
  15. data/config/templates/zen/style.sass +24 -0
  16. data/features/config.feature +21 -0
  17. data/features/publish.feature +3 -3
  18. data/features/support/env.rb +9 -27
  19. data/features/templates.feature +79 -0
  20. data/lib/mint.rb +11 -11
  21. data/lib/mint/{commandline.rb → command_line.rb} +96 -80
  22. data/lib/mint/css.rb +43 -34
  23. data/lib/mint/document.rb +99 -93
  24. data/lib/mint/helpers.rb +21 -17
  25. data/lib/mint/layout.rb +1 -1
  26. data/lib/mint/mint.rb +92 -36
  27. data/lib/mint/plugin.rb +5 -5
  28. data/lib/mint/plugins/epub.rb +51 -51
  29. data/lib/mint/resource.rb +2 -2
  30. data/lib/mint/style.rb +2 -2
  31. data/lib/mint/version.rb +1 -1
  32. data/spec/command_line_spec.rb +87 -0
  33. data/spec/css_spec.rb +46 -0
  34. data/spec/document_spec.rb +38 -40
  35. data/spec/helpers_spec.rb +101 -83
  36. data/spec/layout_spec.rb +1 -1
  37. data/spec/mint_spec.rb +184 -60
  38. data/spec/plugin_spec.rb +61 -67
  39. data/spec/plugins/epub_spec.rb +47 -47
  40. data/spec/resource_spec.rb +9 -9
  41. data/spec/spec_helper.rb +20 -93
  42. data/spec/style_spec.rb +6 -8
  43. data/spec/support/fixtures/content.md +16 -0
  44. data/spec/support/fixtures/dynamic.sass +3 -0
  45. data/spec/support/fixtures/layout.haml +3 -0
  46. data/spec/support/fixtures/static.css +3 -0
  47. data/spec/support/matchers.rb +15 -0
  48. metadata +160 -70
  49. data/spec/commandline_spec.rb +0 -91
  50. data/templates/pro/style.sass +0 -0
data/lib/mint.rb CHANGED
@@ -1,11 +1,11 @@
1
- require 'mint/helpers'
2
- require 'mint/mint'
3
- require 'mint/resource'
4
- require 'mint/layout'
5
- require 'mint/style'
6
- require 'mint/document'
7
- require 'mint/version'
8
- require 'mint/css'
9
- require 'mint/commandline'
10
- require 'mint/exceptions'
11
- require 'mint/plugin'
1
+ require "mint/helpers"
2
+ require "mint/mint"
3
+ require "mint/resource"
4
+ require "mint/layout"
5
+ require "mint/style"
6
+ require "mint/document"
7
+ require "mint/version"
8
+ require "mint/css"
9
+ require "mint/command_line"
10
+ require "mint/exceptions"
11
+ require "mint/plugin"
@@ -1,6 +1,9 @@
1
- require 'pathname'
2
- require 'yaml'
3
- require 'optparse'
1
+ require "pathname"
2
+ require "yaml"
3
+ require "optparse"
4
+ require "fileutils"
5
+
6
+ require "active_support/core_ext/object/blank"
4
7
 
5
8
  module Mint
6
9
  module CommandLine
@@ -14,22 +17,24 @@ module Mint
14
17
  # @return [Hash] a structured set of options that the commandline
15
18
  # executable accepts
16
19
  def self.options
17
- options_file = "../../../#{Mint.files[:syntax]}"
20
+ options_file = "../../../config/#{Mint.files[:syntax]}"
18
21
  YAML.load_file File.expand_path(options_file, __FILE__)
19
22
  end
20
23
 
21
- # Yields each commandline option specified by options_metadata as
22
- # a key/value pair to a block. If the option does not take a param, the value
23
- # will be specified as true.
24
+ # Parses ARGV according to the specified or default commandline syntax
24
25
  #
25
- # @param [Hash, #[]] options_metadata a structured set of options that the executable
26
- # can use to parse commandline configuration options
27
- # @return [OptionParser] an object that will parse ARGV when called
28
- def self.parser(options_metadata=Mint::CommandLine.options)
29
- optparse = OptionParser.new do |opts|
30
- opts.banner = 'Usage: mint [command] files [options]'
31
-
32
- Helpers.symbolize_keys(options_metadata).each do |k,v|
26
+ # @param [Array] argv a list of arguments to parse
27
+ # @param [Hash] opts default parsing options (to specify syntax file)
28
+ # @return [Hash] an object that contains parsed options, remaining arguments,
29
+ # and a help message
30
+ def self.parse(argv, opts={})
31
+ opts = { syntax: options }.merge(opts)
32
+ parsed_options = {}
33
+
34
+ parser = OptionParser.new do |cli|
35
+ cli.banner = "Usage: mint [command] files [options]"
36
+
37
+ Helpers.symbolize_keys(opts[:syntax]).each do |k,v|
33
38
  has_param = v[:parameter]
34
39
 
35
40
  v[:short] = "-#{v[:short]}"
@@ -37,49 +42,20 @@ module Mint
37
42
 
38
43
  if has_param
39
44
  v[:long] << " PARAM"
40
- opts.on v[:short], v[:long], v[:description] do |p|
41
- yield k.to_sym, p
45
+ cli.on v[:short], v[:long], v[:description] do |p|
46
+ parsed_options[k.to_sym] = p
42
47
  end
43
48
  else
44
- opts.on v[:short], v[:long], v[:description] do
45
- yield k, true
49
+ cli.on v[:short], v[:long], v[:description] do
50
+ parsed_options[k.to_sym] = true
46
51
  end
47
52
  end
48
53
  end
49
54
  end
50
- end
51
-
52
- # Returns a hash of all active options specified by file (for all scopes).
53
- # That is, if you specify file as 'config.yaml', this will return the aggregate
54
- # of all config.yaml-specified options in the Mint path, where more local
55
- # members of the path take precedence over more global ones.
56
- #
57
- # @param [String] file a filename pointing to a Mint configuration file
58
- # @return [Hash] a structured set of configuration options
59
- def self.configuration(file=Mint.files[:config])
60
- return nil unless file
61
- config_file = Pathname.new file
62
-
63
- # Merge config options from all config files on the Mint path,
64
- # where more local options take precedence over more global
65
- # options
66
- configuration = Mint.path(true).map {|p| p + config_file }.
67
- select(&:exist?).
68
- map {|p| YAML.load_file p }.
69
- reverse.
70
- reduce(Mint.default_options) {|r,p| r.merge p }
71
-
72
- Helpers.symbolize_keys configuration
73
- end
74
55
 
75
- # Returns all configuration options (as specified by the aggregate
76
- # of all config files), along with opts, where opts take precedence.
77
- #
78
- # @param [Hash] additional options to add to the current configuration
79
- # @return [Hash] a structured set of configuration options with opts
80
- # overriding any options from config files
81
- def self.configuration_with(opts)
82
- configuration.merge opts
56
+ transient_argv = argv.dup
57
+ parser.parse! transient_argv
58
+ { argv: transient_argv, options: parsed_options, help: parser.help }
83
59
  end
84
60
 
85
61
  # Mint built-in commands
@@ -92,19 +68,64 @@ module Mint
92
68
  puts message
93
69
  end
94
70
 
71
+ # Install the named file as a template
72
+ #
95
73
  # @param [File] file the file to install to the appropriate Mint directory
96
74
  # @param [Hash] commandline_options a structured set of options, including
97
75
  # a scope label that the method will use to choose the appropriate
98
76
  # installation directory
99
77
  # @return [void]
100
78
  def self.install(file, commandline_options={})
101
- commandline_options[:local] = true
102
- scope = [:global, :user, :local].
79
+ opts = { scope: :local }.merge(commandline_options)
80
+ scope = [:global, :user].
103
81
  select {|e| commandline_options[e] }.
104
- first
82
+ first || :local
83
+
84
+ filename, ext = file.split "."
85
+
86
+ name = commandline_options[:template] || filename
87
+ type = Mint.css_formats.include?(ext) ? :style : :layout
88
+ destination = Mint.template_path(name, type, :scope => opts[:scope], :ext => ext)
89
+ FileUtils.mkdir_p File.expand_path("#{destination}/..")
105
90
 
106
- directory = Mint.path_for_scope(scope)
107
- FileUtils.copy file, directory
91
+ puts "reading file"
92
+ puts File.read file
93
+
94
+ if File.exist? file
95
+ FileUtils.cp file, destination
96
+ else
97
+ raise "[error] no such file"
98
+ end
99
+ end
100
+
101
+ # Uninstall the named template
102
+ #
103
+ # @param [String] name the name of the template to be uninstalled
104
+ # @param [Hash] commandline_options a structured set of options, including
105
+ # a scope label that the method will use to choose the appropriate
106
+ # installation directory
107
+ # @return [void]
108
+ def self.uninstall(name, commandline_options={})
109
+ opts = { scope: :local }.merge(commandline_options)
110
+ FileUtils.rm_r Mint.template_path(name, :all, :scope => opts[:scope])
111
+ end
112
+
113
+ # List the installed templates
114
+ #
115
+ # @return [void]
116
+ def self.templates(filter=nil, commandline_options={})
117
+ scopes = Mint::SCOPE_NAMES.select do |s|
118
+ commandline_options[s]
119
+ end.presence || Mint::SCOPE_NAMES
120
+
121
+ Mint.templates(:scopes => scopes).
122
+ grep(Regexp.new(filter || "")).
123
+ sort.
124
+ each do |template|
125
+ print File.basename template
126
+ print " [#{template}]" if commandline_options[:verbose]
127
+ puts
128
+ end
108
129
  end
109
130
 
110
131
  # Retrieve named template file (probably a built-in or installed
@@ -115,21 +136,25 @@ module Mint
115
136
  # a layout or style flag that the method will use to choose the appropriate
116
137
  # file to edit
117
138
  # @return [void]
118
- def self.edit(name, commandline_options)
139
+ def self.edit(name, commandline_options={})
119
140
  layout = commandline_options[:layout]
120
141
  style = commandline_options[:style]
121
142
 
122
- if layout and not style
123
- layout_or_style = :layout
124
- elsif style
125
- layout_or_style = :style
143
+ # Allow for convenient editing (edit "default" works just as well
144
+ # as edit :style => "default")
145
+ if style
146
+ name, layout_or_style = style, :style
147
+ elsif layout
148
+ name, layout_or_style = layout, :layout
126
149
  else
127
- puts optparse.help
150
+ layout_or_style = :style
128
151
  end
129
152
 
153
+ abort "[error] no template specified" if name.nil? || name.empty?
154
+
130
155
  file = Mint.lookup_template name, layout_or_style
131
156
 
132
- editor = ENV['EDITOR'] || 'vi'
157
+ editor = ENV["EDITOR"] || "vi"
133
158
  system "#{editor} #{file}"
134
159
  end
135
160
 
@@ -142,9 +167,8 @@ module Mint
142
167
  # @return [void]
143
168
  def self.configure(opts, scope=:local)
144
169
  config_directory = Mint.path_for_scope(scope, true)
145
- config_file = config_directory + Mint.files[:config]
146
- Helpers.ensure_directory config_directory
147
- Helpers.update_yaml! opts, config_file
170
+ FileUtils.mkdir_p config_directory
171
+ Helpers.update_yaml! "#{config_directory}/#{Mint.files[:defaults]}", opts
148
172
  end
149
173
 
150
174
  # Tries to set a config option (at the specified scope) per
@@ -156,7 +180,7 @@ module Mint
156
180
  # a scope label that the method will use to choose the appropriate
157
181
  # scope
158
182
  # @return [void]
159
- def self.set(key, value, commandline_options)
183
+ def self.set(key, value, commandline_options={})
160
184
  commandline_options[:local] = true
161
185
  scope = [:global, :user, :local].
162
186
  select {|e| commandline_options[e] }.
@@ -170,7 +194,7 @@ module Mint
170
194
  #
171
195
  # @return [void]
172
196
  def self.config
173
- puts YAML.dump(configuration)
197
+ puts YAML.dump(Mint.configuration)
174
198
  end
175
199
 
176
200
  # Renders and writes to file all resources described by a document.
@@ -184,18 +208,10 @@ module Mint
184
208
  # @param [Hash, #[]] commandline_options a structured set of configuration options
185
209
  # that will guide Mint.publish!
186
210
  # @return [void]
187
- def self.publish!(files, commandline_options)
188
- documents = []
189
- options = configuration_with commandline_options
190
-
191
- options[:root] ||= Dir.getwd
192
-
193
- # Eventually render_style should be replaced with file
194
- # change detection
195
- render_style = true
196
- files.each do |file|
197
- Document.new(file, options).publish! :render_style => render_style
198
- render_style = false
211
+ def self.publish!(files, commandline_options={})
212
+ options = { root: Dir.getwd }.merge(Mint.configuration_with commandline_options)
213
+ files.each_with_index do |file, idx|
214
+ Document.new(file, options).publish!(:render_style => (idx == 0))
199
215
  end
200
216
  end
201
217
  end
data/lib/mint/css.rb CHANGED
@@ -1,61 +1,70 @@
1
+ require "sass"
2
+
1
3
  module Mint
2
4
  module CSS
3
- def container
4
- 'container'
5
+ def self.container
6
+ "container"
5
7
  end
6
8
 
7
- # Maps a "DSL" onto actual CSS. This is not yet implemented, but
8
- # the plan is to translate this ...
9
+ # Maps a "DSL" onto actual CSS. Translates this ...
9
10
  #
10
11
  # ---
11
12
  # Font: Helvetica
12
- # Margin: 1 in
13
- # Line spacing: 1.25
13
+ # Margin: 1in
14
+ # Orientation: Landscape
14
15
  #
15
16
  # ... into something like:
16
17
  #
17
18
  # #container {
18
- # font: (value specified and cleaned up)
19
- # padding-left: (value specified and cleaned up)
20
- # ...
21
- # p { line-height: (value specified and cleaned up) }
19
+ # font-family: Helvetica;
20
+ # padding-left: 1in;
21
+ # @page { size: landscape };
22
22
  # }
23
- def mappings
23
+ def self.mappings
24
24
  {
25
- font: 'font',
26
- color: 'color',
27
- top_margin: 'padding-top',
28
- bottom_margin: 'padding-bottom',
29
- left_margin: 'padding-left',
30
- right_margin: 'padding-right',
31
- top: 'padding-top',
32
- bottom: 'padding-bottom',
33
- left: 'padding-left',
34
- right: 'padding-right',
35
- height: 'height',
36
- width: 'width',
37
- line_spacing: 'p { line-height: %s }',
38
- bullet: 'bullet-shape',
39
- indentation: 'text-indent',
40
- after_paragraph: 'margin-bottom',
41
- before_paragraph: 'margin-top',
42
- smart_typography: 'optimizeLegibility'
25
+ font: "font-family",
26
+ font_size: "font-size",
27
+ font_color: "color",
28
+ color: "color",
29
+ top_margin: "padding-top",
30
+ top: "padding-top",
31
+ bottom_margin: "padding-bottom",
32
+ bottom: "padding-bottom",
33
+ left_margin: "padding-left",
34
+ left: "padding-left",
35
+ right_margin: "padding-right",
36
+ right: "padding-right",
37
+ height: "height",
38
+ width: "width",
39
+ columns: "column-count",
40
+ column_gap: "column-gap",
41
+ orientation: "@page { size: %s }",
42
+ indentation: "p+p { text-indent: %s }",
43
+ indent: "p+p { text-indent: %s }",
44
+ bullet: "li { list-style-type: %s }",
45
+ bullet_image: "li { list-style-image: url(%s) }",
46
+ after_paragraph: "margin-bottom",
47
+ before_paragraph: "margin-top"
43
48
  }
44
49
  end
45
50
 
46
- def format(key, value)
51
+ def self.stylify(key, value)
47
52
  selector = mappings[Helpers.symbolize key]
48
53
 
49
- if selector.include? '%'
54
+ if selector.nil?
55
+ ""
56
+ elsif selector.include? "%"
50
57
  selector % value
51
58
  else
52
59
  "#{selector || key}: #{value}"
53
60
  end
54
61
  end
55
62
 
56
- def parse(style)
57
- css = style.map {|k,v| format(k, v) }.join("\n ")
58
- "##{container} {\n #{css.strip}\n}"
63
+ def self.parse(style)
64
+ css = style.map {|k,v| stylify(k, v) }.join("\n ")
65
+ container_scope = "##{container}\n #{css.strip}\n"
66
+ engine = Sass::Engine.new(container_scope)
67
+ engine.silence_sass_warnings { engine.render }
59
68
  end
60
69
  end
61
70
  end
data/lib/mint/document.rb CHANGED
@@ -1,15 +1,69 @@
1
- require 'mint/resource'
2
- require 'mint/layout'
3
- require 'mint/style'
1
+ require "mint/resource"
2
+ require "mint/layout"
3
+ require "mint/style"
4
4
 
5
5
  module Mint
6
6
  class Document < Resource
7
7
  METADATA_DELIM = "\n\n"
8
8
 
9
+ # Creates a new Mint Document object. Can be block initialized.
10
+ # Accepts source and options. Block initialization occurs after
11
+ # all defaults are set, so not all options must be specified.
12
+ def initialize(source, opts={})
13
+ options = Mint.default_options.merge opts
14
+
15
+ # Loads source and destination, which will be used for
16
+ # all source_* and destination_* virtual attributes.
17
+ super(source, options)
18
+ self.type = :document
19
+
20
+ # Each of these should invoke explicitly defined method
21
+ self.content = source
22
+ self.layout = options[:layout]
23
+ self.style = options[:style]
24
+ self.style_destination = options[:style_destination]
25
+
26
+ # The template option will override layout and style choices
27
+ self.template = options[:template]
28
+
29
+ # Yield self to block after all other parameters are loaded,
30
+ # so we only have to tweak. (We don't have to give up our
31
+ # defaults or re-test blocks beyond them being tweaked.)
32
+ yield self if block_given?
33
+ end
34
+
35
+ # Renders content in the context of layout and returns as a String.
36
+ def render(args={})
37
+ intermediate_content = layout.render self, args
38
+ Mint.after_render(intermediate_content)
39
+ end
40
+
41
+ # Writes all rendered content where a) possible, b) required,
42
+ # and c) specified. Outputs to specified file.
43
+ def publish!(opts={})
44
+ options = { :render_style => true }.merge(opts)
45
+ FileUtils.mkdir_p self.destination_directory
46
+ File.open(self.destination_file, "w+") do |f|
47
+ f << self.render
48
+ end
49
+
50
+ # Only renders style if a) it's specified by the options path and
51
+ # b) it actually needs rendering (i.e., it's in template form and
52
+ # not raw, browser-parseable CSS) or it if it doesn't need
53
+ # rendering but there is an explicit style_destination.
54
+ if options[:render_style]
55
+ FileUtils.mkdir_p style_destination_directory
56
+ File.open(self.style_destination_file, "w+") do |f|
57
+ f << self.style.render
58
+ end
59
+ end
60
+
61
+ Mint.after_publish(self, opts)
62
+ end
63
+
9
64
  # Implicit readers are paired with explicit accessors. This
10
65
  # allows for processing variables before storing them.
11
- attr_reader :content, :layout, :style
12
- attr_accessor :metadata
66
+ attr_reader :content, :metadata, :layout, :style
13
67
 
14
68
  # Passes content through a renderer before assigning it to be
15
69
  # the Document's content
@@ -21,11 +75,12 @@ module Mint
21
75
  tempfile = Helpers.generate_temp_file! content
22
76
  original_content = File.read content
23
77
 
24
- metadata, text = Document.parse_metadata_from original_content
25
- self.metadata = metadata
78
+ @metadata, text = Document.parse_metadata_from original_content
26
79
  intermediate_content = Mint.before_render text
27
80
 
28
- File.open(tempfile, 'w') {|file| file << intermediate_content }
81
+ File.open(tempfile, "w") do |file|
82
+ file << intermediate_content
83
+ end
29
84
 
30
85
  @renderer = Mint.renderer tempfile
31
86
  @content = @renderer.render
@@ -65,6 +120,17 @@ module Mint
65
120
  abort "Template '#{style}' does not exist."
66
121
  end
67
122
 
123
+ # Overrides layout and style settings with named template.
124
+ #
125
+ # @param [String] template the name of the template to set as
126
+ # layout and string
127
+ def template=(template)
128
+ if template
129
+ self.layout = template
130
+ self.style = template
131
+ end
132
+ end
133
+
68
134
  # Explanation of style_destination:
69
135
  #
70
136
  # I'm going to maintain a document's official style_destination
@@ -126,72 +192,6 @@ module Mint
126
192
  style_destination_directory_path.to_s
127
193
  end
128
194
 
129
- # Overrides layout and style settings with named template.
130
- #
131
- # @param [String] template the name of the template to set as
132
- # layout and string
133
- def template=(template)
134
- if template
135
- self.layout = template
136
- self.style = template
137
- end
138
- end
139
-
140
- # Creates a new Mint Document object. Can be block initialized.
141
- # Accepts source and options. Block initialization occurs after
142
- # all defaults are set, so not all options must be specified.
143
- def initialize(source, opts={})
144
- options = Mint.default_options.merge opts
145
-
146
- # Loads source and destination, which will be used for
147
- # all source_* and destination_* virtual attributes.
148
- super(source, options)
149
- self.type = :document
150
-
151
- # Each of these should invoke explicitly defined method
152
- self.content = source
153
- self.layout = options[:layout]
154
- self.style = options[:style]
155
- self.style_destination = options[:style_destination]
156
-
157
- # The template option will override layout and style choices
158
- self.template = options[:template]
159
-
160
- # Yield self to block after all other parameters are loaded,
161
- # so we only have to tweak. (We don't have to give up our
162
- # defaults or re-test blocks beyond them being tweaked.)
163
- yield self if block_given?
164
- end
165
-
166
- # Renders content in the context of layout and returns as a String.
167
- def render(args={})
168
- intermediate_content = layout.render self, args
169
- Mint.after_render(intermediate_content)
170
- end
171
-
172
- # Writes all rendered content where a) possible, b) required,
173
- # and c) specified. Outputs to specified file.
174
- def publish!(opts={})
175
- options = { :render_style => true }.merge(opts)
176
- FileUtils.mkdir_p self.destination_directory
177
- File.open(self.destination_file, 'w+') do |f|
178
- f << self.render
179
- end
180
-
181
- # Only renders style if a) it's specified by the options path and
182
- # b) it actually needs rendering (i.e., it's in template form and
183
- # not raw, browser-parseable CSS) or it if it doesn't need
184
- # rendering but there is an explicit style_destination.
185
- if options[:render_style]
186
- FileUtils.mkdir_p style_destination_directory
187
- File.open(self.style_destination_file, 'w+') do |f|
188
- f << self.style.render
189
- end
190
- end
191
-
192
- Mint.after_publish(self, opts)
193
- end
194
-
195
195
  # Convenience methods for views
196
196
 
197
197
  # Returns a relative path from the document to its stylesheet. Can
@@ -201,29 +201,35 @@ module Mint
201
201
  self.destination_directory).to_s
202
202
  end
203
203
 
204
- protected
205
-
206
- def self.metadata_chunk(text)
207
- text.split(METADATA_DELIM).first
204
+ def inline_styles
205
+ CSS.parse(metadata)
208
206
  end
209
207
 
210
- def self.metadata_from(text)
211
- raw_metadata = YAML.load metadata_chunk(text)
212
- raw_metadata.is_a?(String) ? {} : raw_metadata
213
- rescue
214
- {}
215
- end
208
+ # Functions
216
209
 
217
- def self.parse_metadata_from(text)
218
- metadata = metadata_from text
219
- new_text =
220
- if !metadata.empty?
221
- text.sub metadata_chunk(text) + METADATA_DELIM, ''
222
- else
223
- text
224
- end
210
+ class << self
211
+ def metadata_chunk(text)
212
+ text.split(METADATA_DELIM).first
213
+ end
225
214
 
226
- [metadata, new_text]
215
+ def metadata_from(text)
216
+ raw_metadata = YAML.load metadata_chunk(text)
217
+ raw_metadata.is_a?(String) ? {} : raw_metadata
218
+ rescue
219
+ {}
220
+ end
221
+
222
+ def parse_metadata_from(text)
223
+ metadata = metadata_from text
224
+ new_text =
225
+ if !metadata.empty?
226
+ text.sub metadata_chunk(text) + METADATA_DELIM, ""
227
+ else
228
+ text
229
+ end
230
+
231
+ [metadata, new_text]
232
+ end
227
233
  end
228
234
  end
229
235
  end