mbrao 1.4.4 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +29 -0
- data/.travis.yml +3 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile +4 -4
- data/doc/ActionView.html +125 -0
- data/doc/ActionView/Template.html +140 -0
- data/doc/ActionView/Template/Handlers.html +3 -3
- data/doc/ActionView/Template/Handlers/MbraoTemplate.html +26 -26
- data/doc/HTML.html +2 -2
- data/doc/HTML/Pipeline.html +2 -2
- data/doc/HTML/Pipeline/KramdownFilter.html +4 -4
- data/doc/Mbrao.html +3 -3
- data/doc/Mbrao/Author.html +29 -29
- data/doc/Mbrao/Content.html +1977 -3644
- data/doc/Mbrao/ContentInterface.html +817 -0
- data/doc/Mbrao/ContentInterface/ClassMethods.html +388 -0
- data/doc/Mbrao/Exceptions.html +1 -1
- data/doc/Mbrao/Exceptions/InvalidDate.html +1 -1
- data/doc/Mbrao/Exceptions/InvalidMetadata.html +1 -1
- data/doc/Mbrao/Exceptions/Parsing.html +1 -1
- data/doc/Mbrao/Exceptions/Rendering.html +1 -1
- data/doc/Mbrao/Exceptions/UnavailableLocalization.html +1 -1
- data/doc/Mbrao/Exceptions/Unimplemented.html +1 -1
- data/doc/Mbrao/Exceptions/UnknownEngine.html +1 -1
- data/doc/Mbrao/Parser.html +12 -12
- data/doc/Mbrao/ParserInterface.html +134 -0
- data/doc/Mbrao/ParserInterface/ClassMethods.html +1724 -0
- data/doc/Mbrao/ParserValidations.html +134 -0
- data/doc/Mbrao/ParserValidations/ClassMethods.html +348 -0
- data/doc/Mbrao/ParsingEngines.html +1 -1
- data/doc/Mbrao/ParsingEngines/Base.html +4 -4
- data/doc/Mbrao/ParsingEngines/PlainText.html +25 -15
- data/doc/Mbrao/RenderingEngines.html +1 -1
- data/doc/Mbrao/RenderingEngines/Base.html +2 -2
- data/doc/Mbrao/RenderingEngines/HtmlPipeline.html +173 -169
- data/doc/Mbrao/Version.html +3 -3
- data/doc/_index.html +51 -24
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +1 -1
- data/doc/index.html +1 -1
- data/doc/method_list.html +63 -69
- data/doc/top-level-namespace.html +2 -2
- data/lib/mbrao.rb +7 -2
- data/lib/mbrao/author.rb +5 -5
- data/lib/mbrao/content.rb +110 -256
- data/lib/mbrao/content_interface.rb +146 -0
- data/lib/mbrao/exceptions.rb +1 -1
- data/lib/mbrao/integrations/rails.rb +48 -42
- data/lib/mbrao/parser.rb +24 -176
- data/lib/mbrao/parser_interface.rb +143 -0
- data/lib/mbrao/parser_validations.rb +41 -0
- data/lib/mbrao/parsing_engines/base.rb +4 -4
- data/lib/mbrao/parsing_engines/plain_text.rb +136 -121
- data/lib/mbrao/rendering_engines/base.rb +2 -2
- data/lib/mbrao/rendering_engines/html_pipeline.rb +52 -77
- data/lib/mbrao/rendering_engines/html_pipeline/kramdown_filter.rb +31 -0
- data/lib/mbrao/version.rb +2 -2
- data/mbrao.gemspec +3 -3
- data/spec/mbrao/author_spec.rb +1 -1
- data/spec/mbrao/content_spec.rb +1 -1
- data/spec/mbrao/parser_spec.rb +16 -16
- data/spec/mbrao/rendering_engines/html_pipeline/kramdown_filter_spec.rb +28 -0
- data/spec/mbrao/rendering_engines/html_pipeline_spec.rb +0 -21
- metadata +23 -8
@@ -0,0 +1,143 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the mbrao gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
|
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 ParserInterface
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
# Class methods.
|
14
|
+
#
|
15
|
+
# @attribute 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
|
+
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
|
+
instance.render(content, options, context)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns an object as a JSON compatible hash
|
67
|
+
#
|
68
|
+
# @param target [Object] The target to serialize.
|
69
|
+
# @param keys [Array] The attributes to include in the serialization.
|
70
|
+
# @param options [Hash] Options to modify behavior of the serialization.
|
71
|
+
# The only supported value are:
|
72
|
+
#
|
73
|
+
# * `:exclude`, an array of attributes to skip.
|
74
|
+
# * `:exclude_empty`, if to exclude nil values. Default is `false`.
|
75
|
+
# @return [Hash] An hash with all attributes.
|
76
|
+
def as_json(target, keys, options = {})
|
77
|
+
include_empty = !options[:exclude_empty].to_boolean
|
78
|
+
exclude = options[:exclude].ensure_array(nil, true, true, true, :ensure_string)
|
79
|
+
keys = keys.ensure_array(nil, true, true, true, :ensure_string)
|
80
|
+
|
81
|
+
map_to_json(target, (keys - exclude), include_empty)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Instantiates a new engine for rendering or parsing.
|
85
|
+
#
|
86
|
+
# @param cls [String|Symbol|Object] If a `String` or a `Symbol`, then it will be the class of the engine.
|
87
|
+
# @param type [Symbol] The type or engine. Can be `:parsing` or `:rendering`.
|
88
|
+
# @return [Object] A new engine.
|
89
|
+
def create_engine(cls, type = :parsing)
|
90
|
+
type = :parsing if type != :rendering
|
91
|
+
::Lazier.find_class(cls, "::Mbrao::#{type.to_s.classify}Engines::%CLASS%").new
|
92
|
+
rescue NameError
|
93
|
+
raise Mbrao::Exceptions::UnknownEngine
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns a unique (singleton) instance of the parser.
|
97
|
+
#
|
98
|
+
# @param force [Boolean] If to force recreation of the instance.
|
99
|
+
# @return [Parser] The unique (singleton) instance of the parser.
|
100
|
+
def instance(force = false)
|
101
|
+
@instance = nil if force
|
102
|
+
@instance ||= Mbrao::Parser.new
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
# Returns an attribute or a default value.
|
108
|
+
#
|
109
|
+
# @param attr [Object ]The attribute to return.
|
110
|
+
# @param default_value [Object] The value to return if `attr` is blank.
|
111
|
+
# @param sanitizer [Symbol] An optional method to sanitize the returned value.
|
112
|
+
def attribute_or_default(attr, default_value = nil, sanitizer = :ensure_string)
|
113
|
+
rv = attr.present? ? attr : default_value
|
114
|
+
rv = rv.send(sanitizer) if sanitizer
|
115
|
+
rv
|
116
|
+
end
|
117
|
+
|
118
|
+
# Perform the mapping to JSON.
|
119
|
+
#
|
120
|
+
# @param target [Object] The target to serialize.
|
121
|
+
# @param keys [Array] The attributes to include in the serialization.
|
122
|
+
# @param include_empty [Boolean], if to include nil values.
|
123
|
+
# @return [Hash] An hash with all attributes.
|
124
|
+
def map_to_json(target, keys, include_empty)
|
125
|
+
keys.reduce({}) { |rv, key|
|
126
|
+
value = get_json_field(target, key)
|
127
|
+
rv[key] = value if include_empty || value.present?
|
128
|
+
rv
|
129
|
+
}.deep_stringify_keys
|
130
|
+
end
|
131
|
+
|
132
|
+
# Get a field as JSON.
|
133
|
+
#
|
134
|
+
# @param target [Object] The object containing the value.
|
135
|
+
# @param method [Symbol] The method containing the value.
|
136
|
+
def get_json_field(target, method)
|
137
|
+
value = target.send(method)
|
138
|
+
value = value.as_json if value && value.respond_to?(:as_json) && !value.is_a?(Symbol)
|
139
|
+
value
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the mbrao gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
|
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 perform validations.
|
10
|
+
module ParserValidations
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
# Class methods.
|
14
|
+
module ClassMethods
|
15
|
+
# Checks if the text is a valid email.
|
16
|
+
#
|
17
|
+
# @param text [String] The text to check.
|
18
|
+
# @return [Boolean] `true` if the string is valid email, `false` otherwise.
|
19
|
+
def email?(text)
|
20
|
+
/^([a-z0-9_\.\-\+]+)@([\da-z\.\-]+)\.([a-z\.]{2,6})$/i.match(text.ensure_string.strip)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Checks if the text is a valid URL.
|
24
|
+
#
|
25
|
+
# @param text [String] The text to check.
|
26
|
+
# @return [Boolean] `true` if the string is valid URL, `false` otherwise.
|
27
|
+
def url?(text)
|
28
|
+
%r{
|
29
|
+
^(
|
30
|
+
([a-z0-9\-]+:\/\/) #PROTOCOL
|
31
|
+
(([\w-]+\.)?) # LOWEST TLD
|
32
|
+
([\w-]+) # 2nd LEVEL TLD
|
33
|
+
(\.[a-z]+) # TOP TLD
|
34
|
+
((:\d+)?) # PORT
|
35
|
+
([\S|\?]*) # PATH, QUERYSTRING AND FRAGMENT
|
36
|
+
)$
|
37
|
+
}ix.match(text.ensure_string.strip)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -15,7 +15,7 @@ module Mbrao
|
|
15
15
|
# @param _options [Hash] Options to customize parsing.
|
16
16
|
# @return [Array] An array of metadata and contents parts.
|
17
17
|
def separate_components(_content, _options = {})
|
18
|
-
raise Mbrao::Exceptions::Unimplemented
|
18
|
+
raise Mbrao::Exceptions::Unimplemented
|
19
19
|
end
|
20
20
|
|
21
21
|
# Parses metadata part and returns all valid metadata.
|
@@ -24,7 +24,7 @@ module Mbrao
|
|
24
24
|
# @param _options [Hash] Options to customize parsing.
|
25
25
|
# @return [Hash] All valid metadata for the content.
|
26
26
|
def parse_metadata(_content, _options = {})
|
27
|
-
raise Mbrao::Exceptions::Unimplemented
|
27
|
+
raise Mbrao::Exceptions::Unimplemented
|
28
28
|
end
|
29
29
|
|
30
30
|
# Filters content of a post by locale.
|
@@ -35,7 +35,7 @@ module Mbrao
|
|
35
35
|
# @return [String|HashWithIndifferentAccess] Return the filtered content in the desired locales. If only one locale is required, then a `String` is
|
36
36
|
# returned, else a `HashWithIndifferentAccess` with locales as keys.
|
37
37
|
def filter_content(_content, _locales = [], _options = {})
|
38
|
-
raise Mbrao::Exceptions::Unimplemented
|
38
|
+
raise Mbrao::Exceptions::Unimplemented
|
39
39
|
end
|
40
40
|
|
41
41
|
# Parses a content and return a {Content Content} object.
|
@@ -49,4 +49,4 @@ module Mbrao
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
52
|
-
end
|
52
|
+
end
|
@@ -17,10 +17,10 @@ module Mbrao
|
|
17
17
|
def separate_components(content, options = {})
|
18
18
|
metadata, content, scanner, start_tag, end_tag = prepare_for_separation(content, options)
|
19
19
|
|
20
|
-
if scanner.scan_until(start_tag)
|
20
|
+
if scanner.scan_until(start_tag)
|
21
21
|
metadata = scanner.scan_until(end_tag)
|
22
22
|
|
23
|
-
if metadata
|
23
|
+
if metadata
|
24
24
|
metadata = metadata.partition(end_tag).first
|
25
25
|
content = scanner.rest.strip
|
26
26
|
end
|
@@ -35,10 +35,15 @@ module Mbrao
|
|
35
35
|
# @param options [Hash] Options to customize parsing.
|
36
36
|
# @return [Hash] All valid metadata for the content.
|
37
37
|
def parse_metadata(content, options = {})
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
rv = YAML.load(content)
|
39
|
+
rv ||= {}
|
40
|
+
raise ArgumentError unless rv.is_a?(Hash)
|
41
|
+
rv
|
42
|
+
rescue => e
|
43
|
+
if options[:default]
|
44
|
+
options[:default]
|
45
|
+
else
|
46
|
+
raise ::Mbrao::Exceptions::InvalidMetadata, e.to_s
|
42
47
|
end
|
43
48
|
end
|
44
49
|
|
@@ -62,132 +67,142 @@ module Mbrao
|
|
62
67
|
end
|
63
68
|
|
64
69
|
private
|
65
|
-
# Prepare arguments for separation.
|
66
|
-
#
|
67
|
-
# @param content [String] The content to separate.
|
68
|
-
# @param options [Hash] The options to sanitize.
|
69
|
-
# @return [Array] The sanitized arguments.
|
70
|
-
def prepare_for_separation(content, options)
|
71
|
-
content = content.ensure_string.strip
|
72
|
-
meta_tags = sanitize_tags(options[:meta_tags], ["{{metadata}}", "{{/metadata}}"])
|
73
|
-
|
74
|
-
[nil, content.ensure_string.strip, StringScanner.new(content), meta_tags.first, meta_tags.last]
|
75
|
-
end
|
76
70
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
71
|
+
# Prepare arguments for separation.
|
72
|
+
#
|
73
|
+
# @param content [String] The content to separate.
|
74
|
+
# @param options [Hash] The options to sanitize.
|
75
|
+
# @return [Array] The sanitized arguments.
|
76
|
+
def prepare_for_separation(content, options)
|
77
|
+
content = content.ensure_string.strip
|
78
|
+
meta_tags = sanitize_tags(options[:meta_tags], ["{{metadata}}", "{{/metadata}}"])
|
79
|
+
|
80
|
+
[nil, content.ensure_string.strip, StringScanner.new(content), meta_tags.first, meta_tags.last]
|
81
|
+
end
|
85
82
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
# Begin scanning the string
|
96
|
-
while !scanner.eos? do
|
97
|
-
if scanner.exist?(start_tag) then # It may start an embedded content
|
98
|
-
# Scan until the start tag, remove the tag from the match and then store to results.
|
99
|
-
rv << [scanner.scan_until(start_tag).partition(start_tag).first, "*"]
|
100
|
-
|
101
|
-
# Keep a reference to the start tag
|
102
|
-
starting = scanner.matched
|
103
|
-
|
104
|
-
# Now try to match the rightmost occurring closing tag
|
105
|
-
embedded = parse_embedded_content(scanner, start_tag, end_tag)
|
106
|
-
|
107
|
-
# Append results
|
108
|
-
rv << get_embedded_content(starting, embedded, start_tag, end_tag)
|
109
|
-
else # Append the rest to the result.
|
110
|
-
rv << [scanner.rest, "*"]
|
111
|
-
scanner.terminate
|
112
|
-
end
|
113
|
-
end
|
83
|
+
# Sanitizes tag markers.
|
84
|
+
#
|
85
|
+
# @param tag [Array|String] The tag to sanitize.
|
86
|
+
# @return [Array] Sanitized tags.
|
87
|
+
def sanitize_tags(tag, default = ["---"])
|
88
|
+
tag = tag.ensure_string.split(/\s*,\s*/).map(&:strip) if tag && !tag.is_a?(Array)
|
89
|
+
(tag.present? ? tag : default).slice(0, 2).map { |t| /#{Regexp.quote(t).gsub("%ARGS%", "\\s*(?<args>[^\\n\\}]+,?)*")}/ }
|
90
|
+
end
|
114
91
|
|
115
|
-
|
116
|
-
|
92
|
+
# Scans a text and content section.
|
93
|
+
#
|
94
|
+
# @param content [String] The string to scan
|
95
|
+
# @param start_tag [Regexp] The tag to match for starting section.
|
96
|
+
# @param end_tag [Regexp] The tag to match for ending section.
|
97
|
+
# @return [String] The result of the scan.
|
98
|
+
def scan_content(content, start_tag, end_tag)
|
99
|
+
rv = []
|
100
|
+
scanner = StringScanner.new(content)
|
101
|
+
|
102
|
+
# Begin scanning the string
|
103
|
+
perform_scan(rv, scanner, start_tag, end_tag) until scanner.eos?
|
104
|
+
|
105
|
+
rv
|
106
|
+
end
|
117
107
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
#
|
127
|
-
|
108
|
+
# Perform a scan on the text and content.
|
109
|
+
#
|
110
|
+
# @param rv [String] The string where to put the results.
|
111
|
+
# @param scanner [StringScanner] The scanner to use.
|
112
|
+
# @param start_tag [Regexp] The tag to match for starting section.
|
113
|
+
# @param end_tag [Regexp] The tag to match for ending section.
|
114
|
+
def perform_scan(rv, scanner, start_tag, end_tag)
|
115
|
+
if scanner.exist?(start_tag) # It may start an embedded content
|
116
|
+
# Scan until the start tag, remove the tag from the match and then store to results.
|
117
|
+
rv << [scanner.scan_until(start_tag).partition(start_tag).first, "*"]
|
118
|
+
|
119
|
+
# Keep a reference to the start tag
|
120
|
+
starting = scanner.matched
|
121
|
+
|
122
|
+
# Now try to match the rightmost occurring closing tag and then append results
|
123
|
+
embedded = parse_embedded_content(scanner, start_tag, end_tag)
|
124
|
+
|
125
|
+
# Append results
|
126
|
+
rv << get_embedded_content(starting, embedded, start_tag, end_tag)
|
127
|
+
else # Append the rest to the result.
|
128
|
+
rv << [scanner.rest, "*"]
|
129
|
+
scanner.terminate
|
128
130
|
end
|
131
|
+
end
|
129
132
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
while balance > 0 && embedded_part do
|
142
|
-
balance += embedded_part.scan(start_tag).count - 1 # -1 Because there is a closure
|
143
|
-
embedded_part = embedded_part.partition(end_tag).first if balance == 0 || !scanner.exist?(end_tag) # This is the last occurrence.
|
144
|
-
rv << embedded_part
|
145
|
-
embedded_part = scanner.scan_until(end_tag) if balance > 0
|
146
|
-
end
|
133
|
+
# Gets results for an embedded content.
|
134
|
+
#
|
135
|
+
# @param [String] starting The match starting expression.
|
136
|
+
# @param [String] embedded The embedded contents.
|
137
|
+
# @param start_tag [Regexp] The tag to match for starting section.
|
138
|
+
# @param end_tag [Regexp] The tag to match for ending section.
|
139
|
+
# @return [Array] An array which the first element is the list of valid contents and second is the list of valid locales.
|
140
|
+
def get_embedded_content(starting, embedded, start_tag, end_tag)
|
141
|
+
# Either we have some content or the content was not closed and therefore we ignore this tag.
|
142
|
+
embedded.present? ? [scan_content(embedded, start_tag, end_tag), starting.match(start_tag)["args"]] : [starting, "*"]
|
143
|
+
end
|
147
144
|
|
148
|
-
|
145
|
+
# Parses embedded content of a tag
|
146
|
+
#
|
147
|
+
# @param scanner [StringScanner] The scanner to use.
|
148
|
+
# @param start_tag [Regexp] The tag to match for starting section.
|
149
|
+
# @param end_tag [Regexp] The tag to match for ending section.
|
150
|
+
# @return [String] The embedded content or `nil`, if the content was never closed.
|
151
|
+
def parse_embedded_content(scanner, start_tag, end_tag)
|
152
|
+
rv = ""
|
153
|
+
balance = 1
|
154
|
+
embedded_part = scanner.scan_until(end_tag)
|
155
|
+
|
156
|
+
while balance > 0 && embedded_part
|
157
|
+
balance += embedded_part.scan(start_tag).count - 1 # -1 Because there is a closure
|
158
|
+
embedded_part = embedded_part.partition(end_tag).first if balance == 0 || !scanner.exist?(end_tag) # This is the last occurrence.
|
159
|
+
rv << embedded_part
|
160
|
+
embedded_part = scanner.scan_until(end_tag) if balance > 0
|
149
161
|
end
|
150
162
|
|
151
|
-
|
152
|
-
|
153
|
-
# @param content [Array] The content to filter. @see #scan_content.
|
154
|
-
# @param locales [Array] The desired locales. Can include `*` to match all.
|
155
|
-
# @return [String|nil] Return the filtered content or `nil` if the content must be hidden.
|
156
|
-
def perform_filter_content(content, locales)
|
157
|
-
content.map { |part|
|
158
|
-
part_content = part[0]
|
159
|
-
part_locales = parse_locales(part[1])
|
160
|
-
|
161
|
-
if locales_valid?(locales, part_locales) then
|
162
|
-
part_content.is_a?(Array) ? perform_filter_content(part_content, locales) : part_content
|
163
|
-
else
|
164
|
-
nil
|
165
|
-
end
|
166
|
-
}.compact.join("")
|
167
|
-
end
|
163
|
+
rv
|
164
|
+
end
|
168
165
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
166
|
+
# Filters content by locale.
|
167
|
+
#
|
168
|
+
# @param content [Array] The content to filter. @see #scan_content.
|
169
|
+
# @param locales [Array] The desired locales. Can include `*` to match all.
|
170
|
+
# @return [String|nil] Return the filtered content or `nil` if the content must be hidden.
|
171
|
+
def perform_filter_content(content, locales)
|
172
|
+
content.map { |part|
|
173
|
+
part_content = part[0]
|
174
|
+
part_locales = parse_locales(part[1])
|
175
|
+
|
176
|
+
if locales_valid?(locales, part_locales)
|
177
|
+
part_content.is_a?(Array) ? perform_filter_content(part_content, locales) : part_content
|
178
|
+
else
|
179
|
+
nil
|
180
|
+
end
|
181
|
+
}.compact.join("")
|
182
|
+
end
|
179
183
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
184
|
+
# Parses locales of a content.
|
185
|
+
#
|
186
|
+
# @param locales [String] The desired locales. Can include `*` to match all. Note that `!*` is ignored.
|
187
|
+
# @return [Hash] An hash with valid and invalid locales.
|
188
|
+
def parse_locales(locales)
|
189
|
+
types = locales.split(/\s*,\s*/).map(&:strip).group_by { |l| l !~ /^!/ ? "valid" : "invalid" }
|
190
|
+
types["valid"] ||= []
|
191
|
+
types["invalid"] = types.fetch("invalid", []).reject { |l| l == "!*" }.map { |l| l.gsub(/^!/, "") }
|
192
|
+
types
|
193
|
+
end
|
188
194
|
|
189
|
-
|
190
|
-
|
195
|
+
# Checks if all locales in a list are valid for a part.
|
196
|
+
#
|
197
|
+
# @param locales [Array] The desired locales. Can include `*` to match all.
|
198
|
+
# @param part_locales[Hash] An hash with valid and invalid locales.
|
199
|
+
# @return [Boolean] `true` if the locales are valid, `false` otherwise.
|
200
|
+
def locales_valid?(locales, part_locales)
|
201
|
+
valid = part_locales["valid"]
|
202
|
+
invalid = part_locales["invalid"]
|
203
|
+
|
204
|
+
locales.include?("*") || valid.include?("*") || ((valid.empty? || (locales & valid).present?) && (locales & invalid).blank?)
|
205
|
+
end
|
191
206
|
end
|
192
207
|
end
|
193
|
-
end
|
208
|
+
end
|