content_spinning 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/content_spinning/version.rb +1 -1
- data/lib/content_spinning.rb +75 -45
- data/spec/content_spinning_spec.rb +10 -8
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c13ac04efa5b45c6a59cf3bbea6a47ea9bace674
|
4
|
+
data.tar.gz: 32b6b31adbc605a54d3b7673250f3a307c3cc167
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f91381ee1a24e4218b403be1ce88cb2201e456077d110e7db07157af5163783d66a46906c13bdff0fb24badce6b3347809e0da338615c3fe7b03a8babb2827d7
|
7
|
+
data.tar.gz: e95ff3c4eb4435172f871ad9ce119c3fb915bb0cc1cdb0141d81a339475008046aac51042a37ed36e2d9f53e0fabb1a7475fc982b1f53883d440ac0bcd0c2036
|
data/lib/content_spinning.rb
CHANGED
@@ -2,84 +2,114 @@ require "content_spinning/core_ext/string"
|
|
2
2
|
|
3
3
|
module ContentSpinning
|
4
4
|
|
5
|
+
SPIN_BEGIN_FOR_LEVEL = Hash.new { |h, level| h[level] = "__SPIN_BEGIN_#{level}__" }
|
6
|
+
SPIN_END_FOR_LEVEL = Hash.new { |h, level| h[level] = "__SPIN_END_#{level}__" }
|
7
|
+
SPIN_OR_FOR_LEVEL = Hash.new { |h, level| h[level] = "__SPIN_OR_#{level}__" }
|
8
|
+
|
9
|
+
PARTITIONNER_REGEXP_FOR_LEVEL = Hash.new do |h, level|
|
10
|
+
h[level] = /#{SPIN_BEGIN_FOR_LEVEL[level]}.+?#{SPIN_END_FOR_LEVEL[level]}/
|
11
|
+
end
|
12
|
+
|
5
13
|
class << self
|
6
14
|
|
7
15
|
def spin(text)
|
8
|
-
|
9
|
-
|
10
|
-
|
16
|
+
result = parse(clean(text))
|
17
|
+
|
18
|
+
contents = if result[:max_level] == 0
|
19
|
+
[result[:parsed]]
|
20
|
+
else
|
21
|
+
spin_a_level([result[:parsed]], level: result[:max_level])
|
22
|
+
end
|
23
|
+
|
24
|
+
contents.reject!(&:empty?)
|
25
|
+
contents.uniq!
|
11
26
|
|
12
|
-
|
27
|
+
contents
|
13
28
|
end
|
14
29
|
|
30
|
+
EMPTY_SPIN_REGEXP = /\{\|*\}/
|
31
|
+
ONE_CHOICE_SPIN_REGEXP = /\{([^\{\}\|]+)\}/
|
32
|
+
|
15
33
|
def clean(text)
|
34
|
+
cleaned = text.dup
|
35
|
+
|
16
36
|
loop do
|
17
|
-
text_before_run =
|
37
|
+
text_before_run = cleaned.dup
|
18
38
|
|
19
39
|
# Strip empty spin
|
20
|
-
|
40
|
+
cleaned.gsub!(EMPTY_SPIN_REGEXP, "")
|
21
41
|
|
22
42
|
# Remove spin with only one choice
|
23
|
-
|
43
|
+
cleaned.gsub!(ONE_CHOICE_SPIN_REGEXP, '\1')
|
24
44
|
|
25
|
-
break if
|
45
|
+
break if cleaned == text_before_run
|
26
46
|
end
|
27
47
|
|
28
|
-
|
48
|
+
cleaned
|
29
49
|
end
|
30
50
|
|
31
|
-
|
32
|
-
return { parsed: text, max_level: level - 1 } unless text.include?("{")
|
51
|
+
INNER_SPIN_REGEXP = /\{([^\{\}]+)\}/
|
33
52
|
|
34
|
-
|
35
|
-
|
36
|
-
match.gsub!(/\}/, "__SPIN_END_#{level}__")
|
37
|
-
match.gsub!(/\|/, "__SPIN_OR_#{level}__")
|
38
|
-
end
|
53
|
+
def parse(text)
|
54
|
+
parsed = text.dup
|
39
55
|
|
40
|
-
|
41
|
-
|
56
|
+
level = 0
|
57
|
+
loop do
|
58
|
+
level += 1
|
42
59
|
|
43
|
-
|
44
|
-
|
60
|
+
modification_happened = parsed.gsub!(INNER_SPIN_REGEXP) do |match|
|
61
|
+
match.sub!("{", SPIN_BEGIN_FOR_LEVEL[level])
|
62
|
+
match.sub!("}", SPIN_END_FOR_LEVEL[level])
|
63
|
+
match.gsub!("|", SPIN_OR_FOR_LEVEL[level])
|
64
|
+
end
|
45
65
|
|
46
|
-
|
47
|
-
|
48
|
-
|
66
|
+
break unless modification_happened
|
67
|
+
end
|
68
|
+
|
69
|
+
{ parsed: parsed, max_level: level - 1 }
|
70
|
+
end
|
49
71
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
before, vary, after = text.partition(Regexp.new(spin_begin + ".+?" + spin_end))
|
54
|
-
vary.gsub!(Regexp.union(spin_begin, spin_end), "")
|
72
|
+
def spin_a_level(contents, level:)
|
73
|
+
contents.flat_map do |text|
|
74
|
+
parts = extract_parts(text, level: level)
|
55
75
|
|
56
|
-
|
57
|
-
|
76
|
+
parts.map! do |part|
|
77
|
+
spin_a_level(part, level: level - 1)
|
78
|
+
end if level >= 2
|
58
79
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
else
|
63
|
-
varies
|
80
|
+
if parts.length > 1
|
81
|
+
parts[0].product(*parts[1..-1]).tap do |products|
|
82
|
+
products.map!(&:join)
|
64
83
|
end
|
65
84
|
else
|
66
|
-
|
85
|
+
parts[0]
|
67
86
|
end
|
68
87
|
end
|
69
|
-
|
70
|
-
content_array.flatten
|
71
88
|
end
|
72
89
|
|
73
|
-
|
74
|
-
content_array = text_or_array.is_a?(Array) ? text_or_array : [text_or_array]
|
90
|
+
private
|
75
91
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
92
|
+
def extract_parts(text, level:)
|
93
|
+
parts = []
|
94
|
+
|
95
|
+
loop do
|
96
|
+
before, spin, after = text.partition(PARTITIONNER_REGEXP_FOR_LEVEL[level])
|
97
|
+
|
98
|
+
# Before
|
99
|
+
parts << [before] if before != ""
|
100
|
+
|
101
|
+
break if spin == ""
|
102
|
+
|
103
|
+
# Let's vary
|
104
|
+
spin.sub!(SPIN_BEGIN_FOR_LEVEL[level], "")
|
105
|
+
spin.sub!(SPIN_END_FOR_LEVEL[level], "")
|
106
|
+
parts << spin.split(SPIN_OR_FOR_LEVEL[level], -1)
|
107
|
+
|
108
|
+
# After
|
109
|
+
text = after
|
80
110
|
end
|
81
111
|
|
82
|
-
|
112
|
+
parts
|
83
113
|
end
|
84
114
|
|
85
115
|
end
|
@@ -37,6 +37,7 @@ describe ContentSpinning do
|
|
37
37
|
it "keep legitimate spin" do
|
38
38
|
expect(ContentSpinning.clean("{a|b}")).to eq("{a|b}")
|
39
39
|
expect(ContentSpinning.clean("a{b|c}")).to eq("a{b|c}")
|
40
|
+
expect(ContentSpinning.clean("a{b|}")).to eq("a{b|}")
|
40
41
|
expect(ContentSpinning.clean("{{a|b}|c}")).to eq("{{a|b}|c}")
|
41
42
|
end
|
42
43
|
end
|
@@ -89,19 +90,14 @@ describe ContentSpinning do
|
|
89
90
|
expect(ContentSpinning.spin("{a}")).to eq(["a"])
|
90
91
|
expect(ContentSpinning.spin("a{b}")).to eq(["ab"])
|
91
92
|
expect(ContentSpinning.spin("a{b}c")).to eq(["abc"])
|
92
|
-
expect(ContentSpinning.spin("{a}{b}")).to eq(["ab"])
|
93
|
-
expect(ContentSpinning.spin("a{b}{c}d")).to eq(["abcd"])
|
94
93
|
end
|
95
94
|
|
96
95
|
it "manages two spin" do
|
97
|
-
expect(ContentSpinning.spin("{a}")).to eq(["a"])
|
98
|
-
expect(ContentSpinning.spin("a{b}")).to eq(["ab"])
|
99
|
-
expect(ContentSpinning.spin("a{b}c")).to eq(["abc"])
|
100
96
|
expect(ContentSpinning.spin("{a}{b}")).to eq(["ab"])
|
101
97
|
expect(ContentSpinning.spin("a{b}{c}d")).to eq(["abcd"])
|
102
98
|
end
|
103
99
|
|
104
|
-
it "manages spin with an empty
|
100
|
+
it "manages spin with an empty choices" do
|
105
101
|
expect(ContentSpinning.spin("{|a}")).to eq(["a"])
|
106
102
|
expect(ContentSpinning.spin("{|a}b")).to eq(%w(b ab))
|
107
103
|
expect(ContentSpinning.spin("{a|}b")).to eq(%w(ab b))
|
@@ -109,13 +105,14 @@ describe ContentSpinning do
|
|
109
105
|
expect(ContentSpinning.spin("a{b|}{c|}d")).to eq(%w(abcd abd acd ad))
|
110
106
|
end
|
111
107
|
|
112
|
-
it "manages spin with two
|
108
|
+
it "manages spin with two choices" do
|
113
109
|
expect(ContentSpinning.spin("{a|b}")).to eq(%w(a b))
|
114
110
|
expect(ContentSpinning.spin("{a|b}c")).to eq(%w(ac bc))
|
115
111
|
expect(ContentSpinning.spin("{a|b}{c|d}")).to eq(%w(ac ad bc bd))
|
112
|
+
expect(ContentSpinning.spin("{a|b}c{d|e}")).to eq(%w(acd ace bcd bce))
|
116
113
|
end
|
117
114
|
|
118
|
-
it "manages spin with three
|
115
|
+
it "manages spin with three choices" do
|
119
116
|
expect(ContentSpinning.spin("{a|b|c}")).to eq(%w(a b c))
|
120
117
|
expect(ContentSpinning.spin("{a|b|c}d")).to eq(%w(ad bd cd))
|
121
118
|
expect(ContentSpinning.spin("{a|b|c}{d|e}")).to eq(%w(ad ae bd be cd ce))
|
@@ -125,6 +122,11 @@ describe ContentSpinning do
|
|
125
122
|
expect(ContentSpinning.spin("{a{b|c}|d}")).to eq(%w(ab ac d))
|
126
123
|
expect(ContentSpinning.spin("{{a|b}|c}")).to eq(%w(a b c))
|
127
124
|
expect(ContentSpinning.spin("{a|{b|c}}")).to eq(%w(a b c))
|
125
|
+
expect(ContentSpinning.spin("{a|{b|c}}{d|e}")).to eq(%w(ad ae bd be cd ce))
|
126
|
+
end
|
127
|
+
|
128
|
+
it "manages recursive spin with empty choices" do
|
129
|
+
expect(ContentSpinning.spin("{a|{b|{c|{d|e}}}}")).to eq(%w(a b c d e))
|
128
130
|
end
|
129
131
|
|
130
132
|
it "does not return twice the same result" do
|