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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 79295ec814e234e885f05f6a026177cc49384acf
4
- data.tar.gz: b0cee4376b527d0b7a1d1ef0373ff51e385fb8b4
3
+ metadata.gz: c13ac04efa5b45c6a59cf3bbea6a47ea9bace674
4
+ data.tar.gz: 32b6b31adbc605a54d3b7673250f3a307c3cc167
5
5
  SHA512:
6
- metadata.gz: 3b44c72fddeafdd9fda092eb44c38f2a30547f974be9771ebf7fe2e92085ebdaaf6ba25991ce213bd4eb1e1c9db4f619d787ff5986b9e2b26528fce5dd5b0381
7
- data.tar.gz: 22b09a4e78ccc4686a9387fe5b4313f35abf5d92bf7fe8ff490b2d6569424db83dac152770d66f05c7719ad518a027fc846bd10df7006656abad6e54787036bf
6
+ metadata.gz: f91381ee1a24e4218b403be1ce88cb2201e456077d110e7db07157af5163783d66a46906c13bdff0fb24badce6b3347809e0da338615c3fe7b03a8babb2827d7
7
+ data.tar.gz: e95ff3c4eb4435172f871ad9ce119c3fb915bb0cc1cdb0141d81a339475008046aac51042a37ed36e2d9f53e0fabb1a7475fc982b1f53883d440ac0bcd0c2036
@@ -2,7 +2,7 @@ module ContentSpinning
2
2
 
3
3
  module Version
4
4
 
5
- STRING = "0.1.0".freeze
5
+ STRING = "0.2.0".freeze
6
6
 
7
7
  end
8
8
 
@@ -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
- text = text.dup
9
- text = clean(text)
10
- result = parse(text)
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
- spin_all_level(result[:parsed], result[:max_level])
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 = text.dup
37
+ text_before_run = cleaned.dup
18
38
 
19
39
  # Strip empty spin
20
- text.gsub!(/\{\|*\}/, "")
40
+ cleaned.gsub!(EMPTY_SPIN_REGEXP, "")
21
41
 
22
42
  # Remove spin with only one choice
23
- text.gsub!(/\{([^\{\}\|]+)\}/, '\1')
43
+ cleaned.gsub!(ONE_CHOICE_SPIN_REGEXP, '\1')
24
44
 
25
- break if text == text_before_run
45
+ break if cleaned == text_before_run
26
46
  end
27
47
 
28
- text
48
+ cleaned
29
49
  end
30
50
 
31
- def parse(text, level = 1)
32
- return { parsed: text, max_level: level - 1 } unless text.include?("{")
51
+ INNER_SPIN_REGEXP = /\{([^\{\}]+)\}/
33
52
 
34
- text.gsub!(/\{([^\{\}]+)\}/) do |match|
35
- match.gsub!(/\{/, "__SPIN_BEGIN_#{level}__")
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
- parse(text, level + 1)
41
- end
56
+ level = 0
57
+ loop do
58
+ level += 1
42
59
 
43
- def spin_a_level(text_or_array, level)
44
- content_array = text_or_array.is_a?(Array) ? text_or_array : [text_or_array]
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
- spin_begin = "__SPIN_BEGIN_#{level}__"
47
- spin_end = "__SPIN_END_#{level}__"
48
- spin_or = "__SPIN_OR_#{level}__"
66
+ break unless modification_happened
67
+ end
68
+
69
+ { parsed: parsed, max_level: level - 1 }
70
+ end
49
71
 
50
- content_array.map! do |text|
51
- if text.include?(spin_begin)
52
- # Spin a first one
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
- varies = vary.split(Regexp.new(spin_or), -1)
57
- varies.map! { |choice| before + choice + after }
76
+ parts.map! do |part|
77
+ spin_a_level(part, level: level - 1)
78
+ end if level >= 2
58
79
 
59
- # Continue spinning the level if there are other same level spin or just return
60
- if after.include?(spin_begin)
61
- spin_a_level(varies, level).flatten
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
- text
85
+ parts[0]
67
86
  end
68
87
  end
69
-
70
- content_array.flatten
71
88
  end
72
89
 
73
- def spin_all_level(text_or_array, from_level)
74
- content_array = text_or_array.is_a?(Array) ? text_or_array : [text_or_array]
90
+ private
75
91
 
76
- if from_level > 0
77
- (1..from_level).reverse_each do |level|
78
- content_array = spin_a_level(content_array, level)
79
- end
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
- content_array.delete_if(&:empty?).uniq
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 choice" do
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 choice" do
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 choice" do
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: content_spinning
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxime Garcia