mbrao 1.0.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/.gitignore +6 -0
- data/.travis-gemfile +13 -0
- data/.travis.yml +8 -0
- data/.yardopts +1 -0
- data/Gemfile +21 -0
- data/README.md +60 -0
- data/Rakefile +11 -0
- data/doc/ActionView/Template/Handlers/MbraoTemplate.html +568 -0
- data/doc/ActionView/Template/Handlers.html +125 -0
- data/doc/HTML/Pipeline/KramdownFilter.html +354 -0
- data/doc/HTML/Pipeline.html +140 -0
- data/doc/HTML.html +125 -0
- data/doc/Mbrao/Author.html +1402 -0
- data/doc/Mbrao/Content.html +4779 -0
- data/doc/Mbrao/ContentPublicInterface.html +658 -0
- data/doc/Mbrao/Exceptions/InvalidDate.html +133 -0
- data/doc/Mbrao/Exceptions/InvalidMetadata.html +133 -0
- data/doc/Mbrao/Exceptions/Parsing.html +133 -0
- data/doc/Mbrao/Exceptions/Rendering.html +133 -0
- data/doc/Mbrao/Exceptions/UnavailableLocalization.html +133 -0
- data/doc/Mbrao/Exceptions/Unimplemented.html +133 -0
- data/doc/Mbrao/Exceptions/UnknownEngine.html +133 -0
- data/doc/Mbrao/Exceptions.html +125 -0
- data/doc/Mbrao/Parser.html +418 -0
- data/doc/Mbrao/ParsingEngines/Base.html +658 -0
- data/doc/Mbrao/ParsingEngines/PlainText.html +571 -0
- data/doc/Mbrao/ParsingEngines.html +127 -0
- data/doc/Mbrao/PublicInterface/ClassMethods.html +1727 -0
- data/doc/Mbrao/PublicInterface.html +134 -0
- data/doc/Mbrao/RenderingEngines/Base.html +280 -0
- data/doc/Mbrao/RenderingEngines/HtmlPipeline.html +873 -0
- data/doc/Mbrao/RenderingEngines.html +127 -0
- data/doc/Mbrao/Validations/ClassMethods.html +692 -0
- data/doc/Mbrao/Validations.html +134 -0
- data/doc/Mbrao/Version.html +189 -0
- data/doc/Mbrao.html +130 -0
- data/doc/_index.html +395 -0
- data/doc/class_list.html +53 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +338 -0
- data/doc/file.README.html +135 -0
- data/doc/file_list.html +55 -0
- data/doc/frames.html +28 -0
- data/doc/index.html +135 -0
- data/doc/js/app.js +214 -0
- data/doc/js/full_list.js +173 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +516 -0
- data/doc/top-level-namespace.html +112 -0
- data/lib/mbrao/author.rb +61 -0
- data/lib/mbrao/content.rb +300 -0
- data/lib/mbrao/exceptions.rb +38 -0
- data/lib/mbrao/integrations/rails.rb +51 -0
- data/lib/mbrao/parser.rb +276 -0
- data/lib/mbrao/parsing_engines/base.rb +51 -0
- data/lib/mbrao/parsing_engines/plain_text.rb +187 -0
- data/lib/mbrao/rendering_engines/base.rb +22 -0
- data/lib/mbrao/rendering_engines/html_pipeline.rb +147 -0
- data/lib/mbrao/version.rb +25 -0
- data/lib/mbrao.rb +24 -0
- data/mbrao.gemspec +31 -0
- data/spec/coverage_helper.rb +17 -0
- data/spec/mbrao/author_spec.rb +62 -0
- data/spec/mbrao/content_spec.rb +280 -0
- data/spec/mbrao/integrations/rails_spec.rb +92 -0
- data/spec/mbrao/parser_spec.rb +269 -0
- data/spec/mbrao/parsing_engines/base_spec.rb +52 -0
- data/spec/mbrao/parsing_engines/plain_text_spec.rb +141 -0
- data/spec/mbrao/rendering_engines/base_spec.rb +17 -0
- data/spec/mbrao/rendering_engines/html_pipeline_spec.rb +128 -0
- data/spec/spec_helper.rb +15 -0
- metadata +195 -0
@@ -0,0 +1,300 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the mbrao gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Mbrao
|
8
|
+
# Setter methods for the {Content Content} class.
|
9
|
+
module ContentPublicInterface
|
10
|
+
# Checks if the content is available for at least one of the provided locales.
|
11
|
+
#
|
12
|
+
# @param locales [Array] The desired locales. Can include `*` to match all. If none are specified, the default mbrao locale will be used.
|
13
|
+
# @return [Boolean] `true` if the content is available for at least one of the desired locales, `false` otherwise.
|
14
|
+
def enabled_for_locales?(*locales)
|
15
|
+
locales = Mbrao::Parser.sanitized_array(locales).collect(&:strip).reject {|l| l == "*" }
|
16
|
+
@locales.blank? || locales.blank? || (@locales & locales).present?
|
17
|
+
end
|
18
|
+
|
19
|
+
# Gets the title of the content in the desired locales.
|
20
|
+
#
|
21
|
+
# @param locales [String|Array] The desired locales. Can include `*` to match all. If none are specified, the default mbrao locale will be used.
|
22
|
+
# @return [String|HashWithIndifferentAccess] Return the title of the content in the desired locales. If only one locale is required, then a `String` is returned, else a `HashWithIndifferentAccess` with locales as keys.
|
23
|
+
def get_title(locales = [])
|
24
|
+
filter_attribute_for_locales(@title, locales)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Gets the body returning only the portion which are available for the given locales.
|
28
|
+
#
|
29
|
+
# @param locales [String|Array] The desired locales. Can include `*` to match all. If none are specified, the default mbrao locale will be used.
|
30
|
+
# @param engine [String|Symbol|Object] The engine to use to filter contents.
|
31
|
+
# @return [String|HashWithIndifferentAccess] Return the body of the content in the desired locales. If only one locale is required, then a `String` is returned, else a `HashWithIndifferentAccess` with locales as keys.
|
32
|
+
def get_body(locales = [], engine = :plain_text)
|
33
|
+
Mbrao::Parser.create_engine(engine).filter_content(self, locales)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Gets the tags of the content in the desired locales.
|
37
|
+
#
|
38
|
+
# @param locales [String|Array] The desired locales. Can include `*` to match all. If none are specified, the default mbrao locale will be used.
|
39
|
+
# @return [Array|HashWithIndifferentAccess] Return the title of the content in the desired locales. If only one locale is required, then a `Array` is returned, else a `HashWithIndifferentAccess` with locales as keys.
|
40
|
+
def get_tags(locales = [])
|
41
|
+
filter_attribute_for_locales(@tags, locales)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Gets the "more link" text of the content in the desired locales.
|
45
|
+
#
|
46
|
+
# @param locales [String|Array] The desired locales. Can include `*` to match all. If none are specified, the default mbrao locale will be used.
|
47
|
+
# @return [String|HashWithIndifferentAccess] Return the label of the "more link" of the content in the desired locales. If only one locale is required, then a `String` is returned, else a `HashWithIndifferentAccess` with locales as keys.
|
48
|
+
def get_more(locales = [])
|
49
|
+
filter_attribute_for_locales(@more, locales)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
# Filters an attribute basing a set of locales.
|
54
|
+
#
|
55
|
+
# @param attribute [Object|HashWithIndifferentAccess] The desired attribute.
|
56
|
+
# @param locales [String|Array] The desired locales. Can include `*` to match all. If none are specified, the default mbrao locale will be used.
|
57
|
+
# @return [String|HashWithIndifferentAccess] Return the object for desired locales. If only one locale is available, then only a object is returned, else a `HashWithIndifferentAccess` with locales as keys.
|
58
|
+
def filter_attribute_for_locales(attribute, locales)
|
59
|
+
locales = ::Mbrao::Content.validate_locales(locales, self)
|
60
|
+
|
61
|
+
if attribute.is_a?(HashWithIndifferentAccess) then
|
62
|
+
rv = attribute.inject(HashWithIndifferentAccess.new) { |hash, pair| append_value_for_locale(hash, pair[0], locales, pair[1]) }
|
63
|
+
rv.keys.length == 1 ? rv.values.first : rv
|
64
|
+
else
|
65
|
+
attribute
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Adds an value on a hash if enable for requested locales.
|
70
|
+
#
|
71
|
+
# @param hash [Hash] The hash to handle.
|
72
|
+
# @param locale [String] The list of locale (separated by commas) for which the value is available.
|
73
|
+
# @param locales [Array] The list of locale for which this value is requested. Can include `*` to match all. If none are specified, the default mbrao locale will be used.
|
74
|
+
# @param value [Object] The value to add.
|
75
|
+
# @return [Hash] Return the original hash.
|
76
|
+
def append_value_for_locale(hash, locale, locales, value)
|
77
|
+
locale.split(/\s*,\s*/).collect(&:strip).each do |l|
|
78
|
+
hash[l] = value if locales.include?("*") || locales.include?(l)
|
79
|
+
end
|
80
|
+
|
81
|
+
hash
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Represents a parsed content, with its metadata.
|
86
|
+
#
|
87
|
+
# @attribute uid
|
88
|
+
# @return [String] A unique ID for this post. This is only for client uses.
|
89
|
+
# @attribute locales
|
90
|
+
# @return [Array] A list of locales for this content should be visible. An empty list means that there are no limitations.
|
91
|
+
# @attribute title
|
92
|
+
# @return [String|HashWithIndifferentAccess] The content's title. Can be a `String` or an `HashWithIndifferentAccess`, if multiple title are specified for multiple locales.
|
93
|
+
# @attribute body
|
94
|
+
# @return [String|HashWithIndifferentAccess] The content's body. Can be a `String` or an `HashWithIndifferentAccess`, if multiple contents are specified for multiple locales.
|
95
|
+
# @attribute tags
|
96
|
+
# @return [String|HashWithIndifferentAccess] The content's "more link" label. Can be a `String` or an `HashWithIndifferentAccess`, if multiple labels are specified for multiple locales.
|
97
|
+
# @attribute tags
|
98
|
+
# @return [Array|HashWithIndifferentAccess] The tags associated with the content. Can be an `Array` or an `HashWithIndifferentAccess`, if multiple tags set are specified for multiple locales.
|
99
|
+
# @attribute author
|
100
|
+
# @return [Author] The post author.
|
101
|
+
# @attribute created_at
|
102
|
+
# @return [DateTime] The post creation date and time. The timezone is always UTC.
|
103
|
+
# @attribute updated_at
|
104
|
+
# @return [DateTime] The post creation date and time. Defaults to the creation date. The timezone is always UTC.
|
105
|
+
# @attribute metadata
|
106
|
+
# @return [Hash] The full list of metadata of this content.
|
107
|
+
class Content
|
108
|
+
include Mbrao::ContentPublicInterface
|
109
|
+
|
110
|
+
attr_accessor :uid
|
111
|
+
attr_accessor :locales
|
112
|
+
attr_accessor :title
|
113
|
+
attr_accessor :body
|
114
|
+
attr_accessor :tags
|
115
|
+
attr_accessor :more
|
116
|
+
attr_accessor :author
|
117
|
+
attr_accessor :created_at
|
118
|
+
attr_accessor :updated_at
|
119
|
+
attr_accessor :metadata
|
120
|
+
|
121
|
+
# Creates a new content.
|
122
|
+
#
|
123
|
+
# @param uid [String] The UID for this content.
|
124
|
+
def initialize(uid = nil)
|
125
|
+
@uid = uid
|
126
|
+
end
|
127
|
+
|
128
|
+
# Sets the `locales` attribute.
|
129
|
+
#
|
130
|
+
# @param value [Array] The new value for the attribute. If an Hash, keys must be a string with one or locale separated by commas. A empty or "*" will be the default value.
|
131
|
+
def locales=(value)
|
132
|
+
@locales = Mbrao::Parser.sanitized_array(value)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Sets the `title` attribute.
|
136
|
+
#
|
137
|
+
# @param value [String|Hash] The new value for the attribute. If an Hash, keys must be a string with one or locale separated by commas. A empty or "*" will be the default value.
|
138
|
+
def title=(value)
|
139
|
+
@title = value.is_a?(Hash) ? Mbrao::Parser.sanitized_hash(value, :ensure_string) : value.ensure_string
|
140
|
+
end
|
141
|
+
|
142
|
+
# Sets the `body` attribute.
|
143
|
+
#
|
144
|
+
# @param value [String] The new value for the attribute. Can contain locales restriction (like !en), which will must be interpreted using #get_body.
|
145
|
+
def body=(value)
|
146
|
+
@body = value.ensure_string
|
147
|
+
end
|
148
|
+
|
149
|
+
# Sets the `tags` attribute.
|
150
|
+
#
|
151
|
+
# @param value [Array|Hash] The new value for the attribute. If an Hash, keys must be a string with one or locale separated by commas. A empty or "*" will be the default value.
|
152
|
+
def tags=(value)
|
153
|
+
@tags = if value.is_a?(Hash) then
|
154
|
+
values = Mbrao::Parser.sanitized_hash(value)
|
155
|
+
values.each {|k, v| values[k] = Mbrao::Parser.sanitized_array(v, true, true) }
|
156
|
+
@tags = values
|
157
|
+
else
|
158
|
+
Mbrao::Parser.sanitized_array(value, true, true)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Sets the `more` attribute.
|
163
|
+
#
|
164
|
+
# @param value [String|Hash] The new value for the attribute. If an Hash, keys must be a string with one or locale separated by commas. A empty or "*" will be the default value.
|
165
|
+
def more=(value)
|
166
|
+
@more = value.is_a?(Hash) ? Mbrao::Parser.sanitized_hash(value, :ensure_string) : value.ensure_string
|
167
|
+
end
|
168
|
+
|
169
|
+
# Sets the `author` attribute.
|
170
|
+
#
|
171
|
+
# @param value [Author|Hash|Object] The new value for the attribute.
|
172
|
+
def author=(value)
|
173
|
+
if value.is_a?(Mbrao::Author) then
|
174
|
+
@author = value
|
175
|
+
elsif value.is_a?(Hash) then
|
176
|
+
value = Mbrao::Parser.sanitized_hash(value, nil)
|
177
|
+
@author = Mbrao::Author.new(value["name"], value["email"], value["website"], value["image"], value["metadata"], value["uid"])
|
178
|
+
else
|
179
|
+
@author = Mbrao::Author.new(value.ensure_string)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Sets the `created_at` attribute.
|
184
|
+
#
|
185
|
+
# @param value [String|DateTime|Fixnum] The new value for the attribute.
|
186
|
+
def created_at=(value)
|
187
|
+
@created_at = extract_datetime(value)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Sets the `updated_at` attribute.
|
191
|
+
#
|
192
|
+
# @param value [String|DateTime|Fixnum] The new value for the attribute.
|
193
|
+
def updated_at=(value)
|
194
|
+
@updated_at = extract_datetime(value)
|
195
|
+
@updated_at = @created_at if !@updated_at
|
196
|
+
end
|
197
|
+
|
198
|
+
# Gets metadata attribute.
|
199
|
+
#
|
200
|
+
# @return The metadata attribute.
|
201
|
+
def metadata
|
202
|
+
@metadata || {}
|
203
|
+
end
|
204
|
+
|
205
|
+
# Sets the `metadata` attribute.
|
206
|
+
#
|
207
|
+
# @param value [Hash] The new value for the attribute.
|
208
|
+
def metadata=(value)
|
209
|
+
if value.is_a?(Hash) then
|
210
|
+
@metadata = Mbrao::Parser.sanitized_hash(value)
|
211
|
+
else
|
212
|
+
@metadata = HashWithIndifferentAccess.new({raw: value})
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Validates locales for attribute retrieval.
|
217
|
+
#
|
218
|
+
# @param locales [Array] A list of desired locales for an attribute. Can include `*` to match all. If none are specified, the default mbrao locale will be used.
|
219
|
+
# @param content [Content|nil] An optional content to check for availability
|
220
|
+
# @return [Array] The validated list of locales.
|
221
|
+
def self.validate_locales(locales, content = nil)
|
222
|
+
locales = Mbrao::Parser.sanitized_array(locales).collect(&:strip)
|
223
|
+
locales = (locales.empty? ? [Mbrao::Parser.locale] : locales)
|
224
|
+
raise Mbrao::Exceptions::UnavailableLocalization.new if content && !content.enabled_for_locales?(locales)
|
225
|
+
locales
|
226
|
+
end
|
227
|
+
|
228
|
+
# Creates a content with metadata and body.
|
229
|
+
#
|
230
|
+
# @param metadata [Hash] The metadata.
|
231
|
+
# @param body [String] The body of the content.
|
232
|
+
# @return [Content] A new content.
|
233
|
+
def self.create(metadata, body)
|
234
|
+
rv = Mbrao::Content.new
|
235
|
+
rv.body = body.ensure_string.strip
|
236
|
+
assign_metadata(rv, metadata) if metadata.is_a?(Hash)
|
237
|
+
rv
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
# Assigns metadata to a content
|
242
|
+
#
|
243
|
+
# @param content [Content] The content to manipulate.
|
244
|
+
# @param metadata [Hash] The metadata to assign.
|
245
|
+
# @return [Content] The content with metadata.
|
246
|
+
def self.assign_metadata(content, metadata)
|
247
|
+
metadata = metadata.symbolize_keys!
|
248
|
+
|
249
|
+
content.uid = metadata.delete(:uid)
|
250
|
+
content.title = metadata.delete(:title)
|
251
|
+
content.author = Mbrao::Author.create(metadata.delete(:author))
|
252
|
+
content.tags = metadata.delete(:tags)
|
253
|
+
content.more = metadata.delete(:more)
|
254
|
+
content.created_at = metadata.delete(:created_at)
|
255
|
+
content.updated_at = metadata.delete(:updated_at)
|
256
|
+
content.locales = extract_locales(metadata)
|
257
|
+
content.metadata = metadata
|
258
|
+
|
259
|
+
content
|
260
|
+
end
|
261
|
+
|
262
|
+
# Extract locales from metadata.
|
263
|
+
#
|
264
|
+
# @param metadata [Hash] The metadata that contains the locales.
|
265
|
+
# @return [Array] The locales.
|
266
|
+
def self.extract_locales(metadata)
|
267
|
+
locales = metadata.delete(:locales)
|
268
|
+
locales = locales.ensure_string.split(/\s*,\s*/) if !locales.is_a?(::Array)
|
269
|
+
normalize_locales(locales)
|
270
|
+
end
|
271
|
+
|
272
|
+
# Normalize locales for further usage.
|
273
|
+
#
|
274
|
+
# @param locales [Array] The locales to normalize.
|
275
|
+
# @return [Array] The normalized locales.
|
276
|
+
def self.normalize_locales(locales)
|
277
|
+
locales.flatten.collect(&:ensure_string).collect(&:strip).uniq
|
278
|
+
end
|
279
|
+
|
280
|
+
# Extracts a date and time from a value.
|
281
|
+
#
|
282
|
+
# @param value [String|DateTime|Fixnum] The value to parse.
|
283
|
+
# @return [DateTime] The extract values.
|
284
|
+
def extract_datetime(value)
|
285
|
+
begin
|
286
|
+
if value.is_a?(Date) || value.is_a?(Time) then
|
287
|
+
value = value.to_datetime
|
288
|
+
elsif value.to_float > 0 then
|
289
|
+
value = Time.at(value.to_float).to_datetime
|
290
|
+
elsif value && !value.is_a?(DateTime) then
|
291
|
+
value = DateTime.strptime(value.ensure_string, "%Y%m%dT%H%M%S%z")
|
292
|
+
end
|
293
|
+
|
294
|
+
value ? value.utc : nil
|
295
|
+
rescue ArgumentError => _
|
296
|
+
raise Mbrao::Exceptions::InvalidDate.new
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the mbrao gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Mbrao
|
8
|
+
# The exceptions raised by mbrao.
|
9
|
+
module Exceptions
|
10
|
+
# Exception raised when metadata are not valid.
|
11
|
+
class InvalidMetadata < ::Exception
|
12
|
+
end
|
13
|
+
|
14
|
+
# Exception raised when a date is valid.
|
15
|
+
class InvalidDate < ::Exception
|
16
|
+
end
|
17
|
+
|
18
|
+
# Exception raised when there is a parsing error.
|
19
|
+
class Parsing < ::Exception
|
20
|
+
end
|
21
|
+
|
22
|
+
# Exception raised when there is a rendering error.
|
23
|
+
class Rendering < ::Exception
|
24
|
+
end
|
25
|
+
|
26
|
+
# Exception raised when a requested object is not available in any of the desired locales.
|
27
|
+
class UnavailableLocalization < ::Exception
|
28
|
+
end
|
29
|
+
|
30
|
+
# Exception raised when a invalid parsing or rendering engine is requested.
|
31
|
+
class UnknownEngine < ::Exception
|
32
|
+
end
|
33
|
+
|
34
|
+
# Exception raised when a requested method must be overridden by a subclass.
|
35
|
+
class Unimplemented < ::Exception
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the mbrao gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
# Generic interface to multiple Ruby template engines.
|
8
|
+
module ActionView::Template::Handlers
|
9
|
+
# Class for rendering mbrao contents in Rails.
|
10
|
+
class MbraoTemplate
|
11
|
+
# Returns a unique (singleton) instance of the template handler.
|
12
|
+
#
|
13
|
+
# @param force [Boolean] If to force recreation of the instance.
|
14
|
+
# @return [MbraoTemplate] The unique (singleton) instance of the template handler.
|
15
|
+
def self.instance(force = false)
|
16
|
+
@instance = nil if force
|
17
|
+
@instance ||= ActionView::Template::Handlers::MbraoTemplate.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# Renders a template into a renderer context.
|
21
|
+
#
|
22
|
+
# @param renderer [Object] The renderer context.
|
23
|
+
# @param template [String] The template to render.
|
24
|
+
# @return [String] The rendered template.
|
25
|
+
def render(renderer, template)
|
26
|
+
content = ::Mbrao::Parser.parse(template)
|
27
|
+
renderer.controller.instance_variable_set(:@mbrao_content, content)
|
28
|
+
renderer.controller.define_singleton_method(:mbrao_content) { @mbrao_content }
|
29
|
+
renderer.controller.send(:helper_method, :mbrao_content)
|
30
|
+
|
31
|
+
::Mbrao::Parser.render(content, {engine: content.metadata[:engine], locale: renderer.controller.params[:locale]})
|
32
|
+
end
|
33
|
+
|
34
|
+
# Declares support for streaming.
|
35
|
+
#
|
36
|
+
# @return [TrueClass] Declares support for streaming.
|
37
|
+
def supports_streaming?
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
# Method called to render a template.
|
42
|
+
#
|
43
|
+
# @param template [ActionView::Template] The template to render.
|
44
|
+
# @return [String] A Ruby snippet to execute to render the template.
|
45
|
+
def call(template)
|
46
|
+
"ActionView::Template::Handlers::MbraoTemplate.instance.render(self, #{template.source.to_json})"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
ActionView::Template.register_template_handler "emt", ActionView::Template::Handlers::MbraoTemplate.instance if defined?(ActionView) && defined?(Rails) && Rails.version =~ /^[34]/
|
data/lib/mbrao/parser.rb
ADDED
@@ -0,0 +1,276 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the mbrao gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
# A content parser and renderer with embedded metadata support.
|
8
|
+
module Mbrao
|
9
|
+
# Methods to allow class level access.
|
10
|
+
module PublicInterface
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
# Class methods.
|
14
|
+
#
|
15
|
+
# @attribute default_locale
|
16
|
+
# @return [String] The mbrao default locale.
|
17
|
+
# @attribute parsing_engine
|
18
|
+
# @return [String] The default parsing engine.
|
19
|
+
# @attribute rendering_engine
|
20
|
+
# @return [String] The default rendering engine.
|
21
|
+
module ClassMethods
|
22
|
+
attr_accessor :locale
|
23
|
+
attr_accessor :parsing_engine
|
24
|
+
attr_accessor :rendering_engine
|
25
|
+
|
26
|
+
# Gets the default locale for mbrao.
|
27
|
+
#
|
28
|
+
# @return [String] The default locale.
|
29
|
+
def locale
|
30
|
+
attribute_or_default(@locale, "en")
|
31
|
+
end
|
32
|
+
|
33
|
+
# Gets the default parsing engine.
|
34
|
+
#
|
35
|
+
# @return [String] The default parsing engine.
|
36
|
+
def parsing_engine
|
37
|
+
attribute_or_default(@parsing_engine, :plain_text, :to_sym)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Gets the default rendering engine.
|
41
|
+
#
|
42
|
+
# @return [String] The default rendering engine.
|
43
|
+
def rendering_engine
|
44
|
+
attribute_or_default(@rendering_engine, :html_pipeline, :to_sym)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Parses a source text.
|
48
|
+
#
|
49
|
+
# @param content [Object] The content to parse.
|
50
|
+
# @param options [Hash] A list of options for parsing.
|
51
|
+
# @return [Content] The parsed data.
|
52
|
+
def parse(content, options = {})
|
53
|
+
self.instance.parse(content, options)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Renders a content.
|
57
|
+
#
|
58
|
+
# @param content [Content] The content to parse.
|
59
|
+
# @param options [Hash] A list of options for renderer.
|
60
|
+
# @param context [Hash] A context for rendering.
|
61
|
+
# @return [String] The rendered content.
|
62
|
+
def render(content, options = {}, context = {})
|
63
|
+
self.instance.render(content, options, context)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Instantiates a new engine for rendering or parsing.
|
67
|
+
#
|
68
|
+
# @param cls [String|Symbol|Object] If a `String` or a `Symbol`, then it will be the class of the engine.
|
69
|
+
# @param type [Symbol] The type or engine. Can be `:parsing` or `:rendering`.
|
70
|
+
# @return [Object] A new engine.
|
71
|
+
def create_engine(cls, type = :parsing)
|
72
|
+
begin
|
73
|
+
type = :parsing if type != :rendering
|
74
|
+
::Mbrao::Parser.find_class(cls, "::Mbrao::#{type.to_s.classify}Engines::%CLASS%").new
|
75
|
+
rescue Mbrao::Exceptions::Unimplemented
|
76
|
+
raise Mbrao::Exceptions::UnknownEngine.new
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Finds a class to instantiate.
|
81
|
+
#
|
82
|
+
# @param cls [Symbol|String|Object] If a `String` or a `Symbol`, then it will be the class to instantiate. Otherwise the class of the object will returned.
|
83
|
+
# @param scope [String] An additional scope to find the class. `%CLASS%` will be substituted with the class name.
|
84
|
+
# @param only_in_scope [Boolean] If only try to instantiate the class in the scope.
|
85
|
+
# @return [Class] The found class.
|
86
|
+
def find_class(cls, scope = "::%CLASS%", only_in_scope = false)
|
87
|
+
if cls.is_a?(String) || cls.is_a?(Symbol) then
|
88
|
+
rv = nil
|
89
|
+
|
90
|
+
cls = cls.to_s.camelize
|
91
|
+
if only_in_scope then
|
92
|
+
cls.gsub!(/^::/, "")
|
93
|
+
else
|
94
|
+
rv = (cls.constantize rescue nil)
|
95
|
+
end
|
96
|
+
|
97
|
+
rv = (scope.ensure_string.gsub("%CLASS%", cls).constantize rescue nil) if !rv && cls !~ /^::/ && scope.present?
|
98
|
+
rv || raise(Mbrao::Exceptions::Unimplemented.new(cls))
|
99
|
+
else
|
100
|
+
cls.class
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns a unique (singleton) instance of the parser.
|
105
|
+
#
|
106
|
+
# @param force [Boolean] If to force recreation of the instance.
|
107
|
+
# @return [Parser] The unique (singleton) instance of the parser.
|
108
|
+
def instance(force = false)
|
109
|
+
@instance = nil if force
|
110
|
+
@instance ||= Mbrao::Parser.new
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
# Returns an attribute or a default value.
|
115
|
+
#
|
116
|
+
# @param attr [Object ]The attribute to return.
|
117
|
+
# @param default_value [Object] The value to return if `attr` is blank.
|
118
|
+
# @param sanitizer [Symbol] An optional method to sanitize the returned value.
|
119
|
+
def attribute_or_default(attr, default_value = nil, sanitizer = :ensure_string)
|
120
|
+
rv = attr.present? ? attr : default_value
|
121
|
+
rv = rv.send(sanitizer) if sanitizer
|
122
|
+
rv
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Methods to perform validations.
|
128
|
+
module Validations
|
129
|
+
extend ActiveSupport::Concern
|
130
|
+
|
131
|
+
# Class methods.
|
132
|
+
module ClassMethods
|
133
|
+
# Checks if the text is a valid email.
|
134
|
+
#
|
135
|
+
# @param text [String] The text to check.
|
136
|
+
# @return [Boolean] `true` if the string is valid email, `false` otherwise.
|
137
|
+
def is_email?(text)
|
138
|
+
regex = /^([a-z0-9_\.\-\+]+)@([\da-z\.\-]+)\.([a-z\.]{2,6})$/i
|
139
|
+
text.ensure_string.strip =~ regex
|
140
|
+
end
|
141
|
+
|
142
|
+
# Checks if the text is a valid URL.
|
143
|
+
#
|
144
|
+
# @param text [String] The text to check.
|
145
|
+
# @return [Boolean] `true` if the string is valid URL, `false` otherwise.
|
146
|
+
def is_url?(text)
|
147
|
+
regex = /
|
148
|
+
^(
|
149
|
+
([a-z0-9\-]+:\/\/) #PROTOCOL
|
150
|
+
(([\w-]+\.)?) # LOWEST TLD
|
151
|
+
([\w-]+) # 2nd LEVEL TLD
|
152
|
+
(\.[a-z]+) # TOP TLD
|
153
|
+
((:\d+)?) # PORT
|
154
|
+
([\S|\?]*) # PATH, QUERYSTRING AND FRAGMENT
|
155
|
+
)$
|
156
|
+
/ix
|
157
|
+
|
158
|
+
text.ensure_string.strip =~ regex
|
159
|
+
end
|
160
|
+
|
161
|
+
# Converts an object making sure that every `Hash` is converted to a `HashWithIndifferentAccess`.
|
162
|
+
#
|
163
|
+
# @param object [Object] The object to convert. If the object is not an Hash or doesn't respond to `collect` then the original object is returned.
|
164
|
+
# @param sanitize_method [Symbol|nil] If not `nil`, the method to use to sanitize entries. Ignored if a block is present.
|
165
|
+
# @param block [Proc] A block to sanitize entries. It must accept the value as unique argument.
|
166
|
+
# @return [Object] The converted object.
|
167
|
+
def sanitized_hash(object, sanitize_method = nil, &block)
|
168
|
+
if object.is_a?(Hash) || object.is_a?(HashWithIndifferentAccess) then
|
169
|
+
object.inject(HashWithIndifferentAccess.new) do |hash, pair|
|
170
|
+
hash[pair[0]] = Mbrao::Parser.sanitized_hash(pair[1], sanitize_method, &block)
|
171
|
+
hash
|
172
|
+
end
|
173
|
+
elsif object.respond_to?(:collect) then
|
174
|
+
object.collect {|item| Mbrao::Parser.sanitized_hash(item, sanitize_method, &block) }
|
175
|
+
else
|
176
|
+
sanitized_hash_entry(object, sanitize_method, &block)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Converts an object to a a flatten array with all values sanitized.
|
181
|
+
#
|
182
|
+
# @param object [Object] The object to convert.
|
183
|
+
# @param uniq [Boolean] If to remove duplicates from the array before sanitizing.
|
184
|
+
# @param compact [Boolean] If to compact the array before sanitizing.
|
185
|
+
# @param sanitize_method [Symbol|nil] If not `nil`, the method to use to sanitize entries. Ignored if a block is present.
|
186
|
+
# @param block [Proc] A block to sanitize entries. It must accept the value as unique argument.
|
187
|
+
# @return [Array] An flattened array whose all values are strings.
|
188
|
+
def sanitized_array(object, uniq = true, compact = false, sanitize_method = :ensure_string, &block)
|
189
|
+
rv = object.ensure_array.flatten
|
190
|
+
rv.uniq! if uniq
|
191
|
+
rv.compact! if compact
|
192
|
+
|
193
|
+
if block then
|
194
|
+
rv = rv.collect(&block)
|
195
|
+
elsif sanitize_method then
|
196
|
+
rv = rv.collect(&sanitize_method)
|
197
|
+
end
|
198
|
+
|
199
|
+
rv.uniq! if uniq
|
200
|
+
rv.compact! if compact
|
201
|
+
rv
|
202
|
+
end
|
203
|
+
|
204
|
+
private
|
205
|
+
# Sanitizes an value for an hash.
|
206
|
+
#
|
207
|
+
# @param value [Object] The value to sanitize.
|
208
|
+
# @param sanitize_method [Symbol|nil] If not `nil`, the method to use to sanitize the value. Ignored if a block is present.
|
209
|
+
# @param block [Proc] A block to sanitize the value. It must accept the value as unique argument.
|
210
|
+
def sanitized_hash_entry(value, sanitize_method = :ensure_string, &block)
|
211
|
+
if block
|
212
|
+
block.call(value)
|
213
|
+
elsif sanitize_method
|
214
|
+
value.send(sanitize_method)
|
215
|
+
else
|
216
|
+
value
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# A parser to handle pipelined content.
|
223
|
+
#
|
224
|
+
class Parser
|
225
|
+
include Mbrao::PublicInterface
|
226
|
+
include Mbrao::Validations
|
227
|
+
|
228
|
+
# Parses a source text.
|
229
|
+
#
|
230
|
+
# @param content [Object] The content to parse.
|
231
|
+
# @param options [Hash] A list of options for parsing.
|
232
|
+
# @return [Content] The parsed data.
|
233
|
+
def parse(content, options = {})
|
234
|
+
options = sanitize_parsing_options(options)
|
235
|
+
::Mbrao::Parser.create_engine(options[:engine]).parse(content, options)
|
236
|
+
end
|
237
|
+
|
238
|
+
# Renders a content.
|
239
|
+
#
|
240
|
+
# @param content [Content] The content to parse.
|
241
|
+
# @param options [Hash] A list of options for renderer.
|
242
|
+
# @param context [Hash] A context for rendering.
|
243
|
+
# @return [String] The rendered content.
|
244
|
+
def render(content, options = {}, context = {})
|
245
|
+
options = sanitize_rendering_options(options)
|
246
|
+
::Mbrao::Parser.create_engine(options[:engine], :rendering).render(content, options, context)
|
247
|
+
end
|
248
|
+
|
249
|
+
private
|
250
|
+
# Sanitizes options for parsing.
|
251
|
+
#
|
252
|
+
# @param options [Hash] The options to sanitize.
|
253
|
+
# @return [HashWithIndifferentAccess] The sanitized options.
|
254
|
+
def sanitize_parsing_options(options)
|
255
|
+
options = (options.is_a?(Hash) ? options : {}).symbolize_keys
|
256
|
+
|
257
|
+
options[:engine] ||= Mbrao::Parser.parsing_engine
|
258
|
+
options[:metadata] = options.fetch(:metadata, true).to_boolean
|
259
|
+
options[:content] = options.fetch(:content, true).to_boolean
|
260
|
+
|
261
|
+
HashWithIndifferentAccess.new(options)
|
262
|
+
end
|
263
|
+
|
264
|
+
# Sanitizes options for rendering.
|
265
|
+
#
|
266
|
+
# @param options [Hash] The options to sanitize.
|
267
|
+
# @return [HashWithIndifferentAccess] The sanitized options.
|
268
|
+
def sanitize_rendering_options(options)
|
269
|
+
options = (options.is_a?(Hash) ? options : {}).symbolize_keys
|
270
|
+
|
271
|
+
options[:engine] ||= Mbrao::Parser.rendering_engine
|
272
|
+
|
273
|
+
HashWithIndifferentAccess.new(options)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|