content_spinning 0.2.0 → 0.3.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: c13ac04efa5b45c6a59cf3bbea6a47ea9bace674
4
- data.tar.gz: 32b6b31adbc605a54d3b7673250f3a307c3cc167
3
+ metadata.gz: 725d38ecb0875c5f125823a80e16105d65875327
4
+ data.tar.gz: feaff568e498f301547e05d5472e7ff4dd9ea4f0
5
5
  SHA512:
6
- metadata.gz: f91381ee1a24e4218b403be1ce88cb2201e456077d110e7db07157af5163783d66a46906c13bdff0fb24badce6b3347809e0da338615c3fe7b03a8babb2827d7
7
- data.tar.gz: e95ff3c4eb4435172f871ad9ce119c3fb915bb0cc1cdb0141d81a339475008046aac51042a37ed36e2d9f53e0fabb1a7475fc982b1f53883d440ac0bcd0c2036
6
+ metadata.gz: 1a1c3bfcd8dc80d0690326333d197e6f4ddae3f19e09abad7d318dddcece9c42be5e4d1448bef2eec17ac59335b6ae2de892fa548ea2bc89107952641d2ebd36
7
+ data.tar.gz: 51550db06f73c46870dfaedc4e90bf913b5cd8f4fbb0b2064d3b6e3bca77b7bf8480633a51f12325d3b4d5d12f2d774a9314a8afebf6966c4d5c52b69715dc57
data/README.md CHANGED
@@ -8,7 +8,7 @@ It manages nested spinning.
8
8
  ```ruby
9
9
  "Hi {there|you}! I'm {efficient|productive}.".spin
10
10
  # or
11
- ContentSpinning.spin "Hi {there|you}! I'm {efficient|productive}."
11
+ ContentSpinning.spin("Hi {there|you}! I'm {efficient|productive}.")
12
12
  ```
13
13
 
14
14
  returns this array :
@@ -28,6 +28,56 @@ returns this array :
28
28
  gem install content_spinning
29
29
  ```
30
30
 
31
+ ## Usage
32
+
33
+ ### All spins
34
+
35
+ Calculating the number of possibilities:
36
+
37
+ ```ruby
38
+ > ContentSpinning.new("Hi {there|you}! I'm {efficient|productive}.").count
39
+
40
+ 4
41
+ ```
42
+
43
+ Generating:
44
+
45
+ ```ruby
46
+ > ContentSpinning.new("Hi {there|you}! I'm {efficient|productive}.").spin
47
+
48
+ [
49
+ "Hi there! I'm efficient.",
50
+ "Hi there! I'm productive.",
51
+ "Hi you! I'm efficient.",
52
+ "Hi you! I'm productive."
53
+ ]
54
+ ```
55
+
56
+ Beware, spins being combinatory, generating all the spins could be quite long.
57
+
58
+ ### Partial spins
59
+
60
+ There is no guaranty of unicity among the results returned (this is random).
61
+ If you ask for a limit greater than the number of possibilities, this returns all the possibilities.
62
+
63
+ ```ruby
64
+ > ContentSpinning.new("Hi {there|you}! I'm {efficient|productive}.").spin(limit: 2)
65
+
66
+ [
67
+ "Hi there! I'm efficient.",
68
+ "Hi you! I'm productive."
69
+ ]
70
+
71
+ > ContentSpinning.new("Hi {there|you}! I'm {efficient|productive}.").spin(limit: 500)
72
+
73
+ [
74
+ "Hi there! I'm efficient.",
75
+ "Hi there! I'm productive.",
76
+ "Hi you! I'm efficient.",
77
+ "Hi you! I'm productive."
78
+ ]
79
+ ```
80
+
31
81
  ## Todo
32
82
 
33
83
  A few things to do :
@@ -1,117 +1,88 @@
1
1
  require "content_spinning/core_ext/string"
2
+ require "content_spinning/sentence"
3
+ require "content_spinning/spinner"
4
+ require "content_spinning/string"
2
5
 
3
- module ContentSpinning
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
6
+ class ContentSpinning
12
7
 
13
8
  class << self
14
9
 
15
- def spin(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!
26
-
27
- contents
10
+ def spin(source, limit: nil)
11
+ new(source).spin(limit: limit)
28
12
  end
29
13
 
30
- EMPTY_SPIN_REGEXP = /\{\|*\}/
31
- ONE_CHOICE_SPIN_REGEXP = /\{([^\{\}\|]+)\}/
32
-
33
- def clean(text)
34
- cleaned = text.dup
14
+ end
35
15
 
36
- loop do
37
- text_before_run = cleaned.dup
16
+ def initialize(source)
17
+ @source = source
18
+ end
38
19
 
39
- # Strip empty spin
40
- cleaned.gsub!(EMPTY_SPIN_REGEXP, "")
20
+ attr_reader :source
41
21
 
42
- # Remove spin with only one choice
43
- cleaned.gsub!(ONE_CHOICE_SPIN_REGEXP, '\1')
22
+ def count
23
+ parse.count
24
+ end
44
25
 
45
- break if cleaned == text_before_run
26
+ SPIN_END = "}"
27
+ SPIN_OR = "|"
28
+ SPIN_START = "{"
29
+
30
+ def parse
31
+ return @root if defined?(@root)
32
+
33
+ heap = [Sentence.new]
34
+
35
+ source.scan(/ [{}|] | [^{}|]+ /x).each do |part|
36
+ current = heap.last
37
+
38
+ if part == SPIN_START
39
+ spinner = ::ContentSpinning::Spinner.new
40
+ current << spinner
41
+ heap << spinner
42
+
43
+ sentence = ::ContentSpinning::Sentence.new
44
+ spinner << sentence
45
+ heap << sentence
46
+ elsif part == SPIN_OR
47
+ heap.pop
48
+ spinner = heap.last
49
+ sentence = ::ContentSpinning::Sentence.new
50
+ spinner << sentence
51
+ heap << sentence
52
+ elsif part == SPIN_END
53
+ heap.pop
54
+ heap.pop
55
+ else
56
+ current << ::ContentSpinning::String.new(part)
46
57
  end
47
-
48
- cleaned
49
58
  end
50
59
 
51
- INNER_SPIN_REGEXP = /\{([^\{\}]+)\}/
52
-
53
- def parse(text)
54
- parsed = text.dup
55
-
56
- level = 0
57
- loop do
58
- level += 1
59
-
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
65
-
66
- break unless modification_happened
67
- end
68
-
69
- { parsed: parsed, max_level: level - 1 }
70
- end
60
+ @root = heap.first.cleaned
61
+ end
71
62
 
72
- def spin_a_level(contents, level:)
73
- contents.flat_map do |text|
74
- parts = extract_parts(text, level: level)
75
-
76
- parts.map! do |part|
77
- spin_a_level(part, level: level - 1)
78
- end if level >= 2
79
-
80
- if parts.length > 1
81
- parts[0].product(*parts[1..-1]).tap do |products|
82
- products.map!(&:join)
83
- end
84
- else
85
- parts[0]
86
- end
87
- end
63
+ def spin(limit: nil)
64
+ if limit && limit < count
65
+ spin_with_limit(limit: limit)
66
+ else
67
+ spin_all
88
68
  end
69
+ end
89
70
 
90
- private
91
-
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)
71
+ def spin_all
72
+ parse.spin
73
+ end
107
74
 
108
- # After
109
- text = after
110
- end
75
+ def spin_with_limit(limit:)
76
+ parsed = parse
111
77
 
112
- parts
78
+ results = Array.new(limit)
79
+ results.map! do
80
+ parsed.random
113
81
  end
82
+ end
114
83
 
84
+ def to_source
85
+ parse.to_source
115
86
  end
116
87
 
117
88
  end
@@ -1,7 +1,7 @@
1
1
  class String
2
2
 
3
- def spin
4
- ContentSpinning.spin(self)
3
+ def spin(limit: nil)
4
+ ContentSpinning.spin(self, limit: limit)
5
5
  end
6
6
 
7
7
  end
@@ -0,0 +1,58 @@
1
+ class ContentSpinning
2
+
3
+ class Sentence < ::Array
4
+
5
+ def initialize(*items)
6
+ push(*items)
7
+ end
8
+
9
+ def cleaned
10
+ map!(&:cleaned)
11
+
12
+ case length
13
+ when 0
14
+ ::ContentSpinning::String.new("")
15
+ when 1
16
+ first
17
+ else
18
+ self
19
+ end
20
+ end
21
+
22
+ def count
23
+ case length
24
+ when 0
25
+ 1
26
+ else
27
+ map(&:count).inject(:*)
28
+ end
29
+ end
30
+
31
+ def inspect
32
+ "<Sentence [#{map(&:inspect).join(", ")}]>"
33
+ end
34
+
35
+ def random
36
+ map(&:random).join
37
+ end
38
+
39
+ def spin
40
+ spinned = map(&:spin)
41
+
42
+ case spinned.length
43
+ when 1
44
+ spinned[0]
45
+ else
46
+ spinned[0].product(*spinned[1..-1]).tap do |products|
47
+ products.map!(&:join)
48
+ end
49
+ end
50
+ end
51
+
52
+ def to_source
53
+ map(&:to_source).join
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,43 @@
1
+ class ContentSpinning
2
+
3
+ class Spinner < ::Array
4
+
5
+ def initialize(*items)
6
+ push(*items)
7
+ end
8
+
9
+ def cleaned
10
+ map!(&:cleaned)
11
+
12
+ uniq!
13
+
14
+ if length == 1
15
+ first
16
+ else
17
+ self
18
+ end
19
+ end
20
+
21
+ def count
22
+ map(&:count).inject(:+)
23
+ end
24
+
25
+ def inspect
26
+ "<Spinner {#{map(&:inspect).join(" | ")}}>"
27
+ end
28
+
29
+ def random
30
+ sample.random
31
+ end
32
+
33
+ def spin
34
+ flat_map(&:spin)
35
+ end
36
+
37
+ def to_source
38
+ "{#{map(&:to_source).join("|")}}"
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,35 @@
1
+ class ContentSpinning
2
+
3
+ class String < ::String
4
+
5
+ def initialize(text)
6
+ self.<<(text)
7
+ end
8
+
9
+ def cleaned
10
+ self
11
+ end
12
+
13
+ def count
14
+ 1
15
+ end
16
+
17
+ def inspect
18
+ "<String {#{inspect}}>"
19
+ end
20
+
21
+ def random
22
+ self
23
+ end
24
+
25
+ def spin
26
+ [self]
27
+ end
28
+
29
+ def to_source
30
+ self
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -1,8 +1,8 @@
1
- module ContentSpinning
1
+ class ContentSpinning
2
2
 
3
3
  module Version
4
4
 
5
- STRING = "0.2.0".freeze
5
+ STRING = "0.3.0".freeze
6
6
 
7
7
  end
8
8
 
@@ -7,7 +7,7 @@ describe String do
7
7
  end
8
8
 
9
9
  it "calls the spin function of ContentSpinning module with the string in argument" do
10
- expect(ContentSpinning).to receive(:spin).with("AaBb")
10
+ expect(ContentSpinning).to receive(:spin).with("AaBb", limit: nil)
11
11
  "AaBb".spin
12
12
  end
13
13
 
@@ -1,76 +1,118 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe ContentSpinning do
4
- describe "#clean" do
5
- it "returns the string if there is no spin" do
6
- expect(ContentSpinning.clean("AaBb")).to eq("AaBb")
4
+
5
+ describe "#count" do
6
+ it "returns an array" do
7
+ expect(ContentSpinning.new("AaBb").count).to eq(1)
7
8
  end
8
9
 
9
- it "strips empty spin" do
10
- expect(ContentSpinning.clean("a{}")).to eq("a")
11
- expect(ContentSpinning.clean("a{|}")).to eq("a")
12
- expect(ContentSpinning.clean("a{||}")).to eq("a")
13
- expect(ContentSpinning.clean("{}a{}")).to eq("a")
14
- expect(ContentSpinning.clean("{}a{|}")).to eq("a")
10
+ it "handles empty spin source" do
11
+ expect(ContentSpinning.new("").count).to eq(1)
12
+ end
13
+
14
+ it "strips empty choices" do
15
+ expect(ContentSpinning.new("a{}").count).to eq(1)
16
+ expect(ContentSpinning.new("a{|}").count).to eq(1)
17
+ expect(ContentSpinning.new("a{||}").count).to eq(1)
18
+ expect(ContentSpinning.new("{}a{}").count).to eq(1)
19
+ expect(ContentSpinning.new("{}a{|}").count).to eq(1)
20
+ end
21
+
22
+ it "keeps empty strings from the returned array" do
23
+ expect(ContentSpinning.new("{|a}").count).to eq(2)
24
+ expect(ContentSpinning.new("{a|}").count).to eq(2)
25
+ end
26
+
27
+ it "manages one spin" do
28
+ expect(ContentSpinning.new("{a}").count).to eq(1)
29
+ expect(ContentSpinning.new("a{b}").count).to eq(1)
30
+ expect(ContentSpinning.new("a{b}c").count).to eq(1)
31
+ end
32
+
33
+ it "manages two spin" do
34
+ expect(ContentSpinning.new("{a}{b}").count).to eq(1)
35
+ expect(ContentSpinning.new("a{b}{c}d").count).to eq(1)
36
+ end
15
37
 
16
- expect(ContentSpinning.clean("a{{}}")).to eq("a")
17
- expect(ContentSpinning.clean("a{{|}}")).to eq("a")
18
- expect(ContentSpinning.clean("a{{}|}")).to eq("a")
38
+ it "manages spin with an empty choices" do
39
+ expect(ContentSpinning.new("{|a}").count).to eq(2)
40
+ expect(ContentSpinning.new("{|a}b").count).to eq(2)
41
+ expect(ContentSpinning.new("{a|}b").count).to eq(2)
42
+ expect(ContentSpinning.new("{a|}{b|}").count).to eq(4)
43
+ expect(ContentSpinning.new("a{b|}{c|}d").count).to eq(4)
44
+ end
19
45
 
20
- expect(ContentSpinning.clean("a{a{}}")).to eq("aa")
46
+ it "manages spin with two choices" do
47
+ expect(ContentSpinning.new("{a|b}").count).to eq(2)
48
+ expect(ContentSpinning.new("{a|b}c").count).to eq(2)
49
+ expect(ContentSpinning.new("{a|b}{c|d}").count).to eq(4)
50
+ expect(ContentSpinning.new("{a|b}c{d|e}").count).to eq(4)
21
51
  end
22
52
 
23
- it "remove spin with no choice" do
24
- expect(ContentSpinning.clean("{a}")).to eq("a")
25
- expect(ContentSpinning.clean("a{b}")).to eq("ab")
26
- expect(ContentSpinning.clean("a{b}c")).to eq("abc")
27
- expect(ContentSpinning.clean("a{b}c{d}e")).to eq("abcde")
53
+ it "manages spin with three choices" do
54
+ expect(ContentSpinning.new("{a|b|c}").count).to eq(3)
55
+ expect(ContentSpinning.new("{a|b|c}d").count).to eq(3)
56
+ expect(ContentSpinning.new("{a|b|c}{d|e}").count).to eq(6)
57
+ end
28
58
 
29
- expect(ContentSpinning.clean("{{a}}")).to eq("a")
30
- expect(ContentSpinning.clean("a{{b}}")).to eq("ab")
31
- expect(ContentSpinning.clean("a{{b}}c")).to eq("abc")
32
- expect(ContentSpinning.clean("a{{b}}c{{d}}e")).to eq("abcde")
59
+ it "manages recursive spin" do
60
+ expect(ContentSpinning.new("{a{b|c}|d}").count).to eq(3)
61
+ expect(ContentSpinning.new("{{a|b}|c}").count).to eq(3)
62
+ expect(ContentSpinning.new("{a|{b|c}}").count).to eq(3)
63
+ expect(ContentSpinning.new("{a|{b|c}}{d|e}").count).to eq(6)
64
+ end
33
65
 
34
- expect(ContentSpinning.clean("{{{a}}}")).to eq("a")
66
+ it "manages recursive spin with empty choices" do
67
+ expect(ContentSpinning.new("{a|{b|{c|{d|e}}}}").count).to eq(5)
35
68
  end
36
69
 
37
- it "keep legitimate spin" do
38
- expect(ContentSpinning.clean("{a|b}")).to eq("{a|b}")
39
- expect(ContentSpinning.clean("a{b|c}")).to eq("a{b|c}")
40
- expect(ContentSpinning.clean("a{b|}")).to eq("a{b|}")
41
- expect(ContentSpinning.clean("{{a|b}|c}")).to eq("{{a|b}|c}")
70
+ it "manages duplicate choices" do
71
+ expect(ContentSpinning.new("{a|a}").count).to eq(1)
42
72
  end
43
73
  end
44
74
 
45
75
  describe "#parse" do
46
76
  it "returns the string if there is no spin" do
47
- expect(ContentSpinning.parse("AaBb")).to eq(max_level: 0, parsed: "AaBb")
77
+ expect(ContentSpinning.new("AaBb").parse).to eq("AaBb")
48
78
  end
49
79
 
50
80
  it "parses simple spin" do
51
- expect(ContentSpinning.parse("{a|b}")).to eq(max_level: 1, parsed: "__SPIN_BEGIN_1__a__SPIN_OR_1__b__SPIN_END_1__")
52
- expect(ContentSpinning.parse("a{b|c}")).to eq(max_level: 1, parsed: "a__SPIN_BEGIN_1__b__SPIN_OR_1__c__SPIN_END_1__")
53
- expect(ContentSpinning.parse("{a|b}c{d|e}")).to eq(max_level: 1, parsed: "__SPIN_BEGIN_1__a__SPIN_OR_1__b__SPIN_END_1__c__SPIN_BEGIN_1__d__SPIN_OR_1__e__SPIN_END_1__")
81
+ expect(ContentSpinning.new("{a|b}").parse).to eq(
82
+ ContentSpinning::Spinner.new("a", "b")
83
+ )
84
+ expect(ContentSpinning.new("a{b|c}").parse).to eq(
85
+ ContentSpinning::Sentence.new(
86
+ "a",
87
+ ContentSpinning::Spinner.new("b", "c")
88
+ )
89
+ )
90
+ expect(ContentSpinning.new("{a|b}c{d|e}").parse).to eq(
91
+ ContentSpinning::Sentence.new(
92
+ ContentSpinning::Spinner.new("a", "b"),
93
+ "c",
94
+ ContentSpinning::Spinner.new("d", "e")
95
+ )
96
+ )
54
97
  end
55
98
 
56
99
  it "manages recursive spin" do
57
- expect(ContentSpinning.parse("{{a|b}|c}")).to eq(max_level: 2, parsed: "__SPIN_BEGIN_2____SPIN_BEGIN_1__a__SPIN_OR_1__b__SPIN_END_1____SPIN_OR_2__c__SPIN_END_2__")
58
- expect(ContentSpinning.parse("{a|{b|c}}")).to eq(max_level: 2, parsed: "__SPIN_BEGIN_2__a__SPIN_OR_2____SPIN_BEGIN_1__b__SPIN_OR_1__c__SPIN_END_1____SPIN_END_2__")
100
+ expect(ContentSpinning.new("{{a|b}|c}").parse).to eq(
101
+ ContentSpinning::Spinner.new(ContentSpinning::Spinner.new("a", "b"), "c")
102
+ )
103
+ expect(ContentSpinning.new("{a|{b|c}}").parse).to eq(
104
+ ContentSpinning::Spinner.new("a", ContentSpinning::Spinner.new("b", "c"))
105
+ )
59
106
  end
60
107
  end
61
108
 
62
- describe "#spin" do
63
- it "calls the clean function of ContentSpinning module with the string in argument" do
64
- expect(ContentSpinning).to receive(:clean).with("AaBb").and_return("AaBb")
65
- ContentSpinning.spin("AaBb")
66
- end
67
-
109
+ describe ".spin" do
68
110
  it "returns an array" do
69
111
  expect(ContentSpinning.spin("AaBb")).to eq(["AaBb"])
70
112
  end
71
113
 
72
- it "returns an empty array if the string to spin is empty" do
73
- expect(ContentSpinning.spin("")).to eq([])
114
+ it "handles empty spin source" do
115
+ expect(ContentSpinning.spin("")).to eq([""])
74
116
  end
75
117
 
76
118
  it "strips empty choices" do
@@ -81,9 +123,9 @@ describe ContentSpinning do
81
123
  expect(ContentSpinning.spin("{}a{|}")).to eq(["a"])
82
124
  end
83
125
 
84
- it "strips empty strings from the returned array" do
85
- expect(ContentSpinning.spin("{|a}")).to eq(["a"])
86
- expect(ContentSpinning.spin("{a|}")).to eq(["a"])
126
+ it "keeps empty strings from the returned array" do
127
+ expect(ContentSpinning.spin("{|a}")).to eq(["", "a"])
128
+ expect(ContentSpinning.spin("{a|}")).to eq(["a", ""])
87
129
  end
88
130
 
89
131
  it "manages one spin" do
@@ -98,10 +140,10 @@ describe ContentSpinning do
98
140
  end
99
141
 
100
142
  it "manages spin with an empty choices" do
101
- expect(ContentSpinning.spin("{|a}")).to eq(["a"])
143
+ expect(ContentSpinning.spin("{|a}")).to eq(["", "a"])
102
144
  expect(ContentSpinning.spin("{|a}b")).to eq(%w(b ab))
103
145
  expect(ContentSpinning.spin("{a|}b")).to eq(%w(ab b))
104
- expect(ContentSpinning.spin("{a|}{b|}")).to eq(%w(ab a b))
146
+ expect(ContentSpinning.spin("{a|}{b|}")).to eq(%w(ab a b) + [""])
105
147
  expect(ContentSpinning.spin("a{b|}{c|}d")).to eq(%w(abcd abd acd ad))
106
148
  end
107
149
 
@@ -139,5 +181,65 @@ describe ContentSpinning do
139
181
  ContentSpinning.spin(source)
140
182
  }.not_to change { source }
141
183
  end
184
+
185
+ context 'with limit' do
186
+ before { @old_seed = Random.srand(2736) }
187
+ after { Random.srand(@old_seed) }
188
+
189
+ it "manages recursive spin with empty choices" do
190
+ expect(ContentSpinning.spin("{a|{b|{c|{d|e}}}}_z", limit: 2)).to eq(%w(d_z a_z))
191
+ end
192
+
193
+ it "manages recursive spin" do
194
+ expect(ContentSpinning.spin("{a|{b|c}}{d|e}_z", limit: 2)).to eq(%w(ce_z ad_z))
195
+ end
196
+ end
197
+ end
198
+
199
+ describe "#to_source" do
200
+ it "returns the string if there is no spin" do
201
+ expect(ContentSpinning.new("AaBb").to_source).to eq("AaBb")
202
+ end
203
+
204
+ it "strips empty spin" do
205
+ expect(ContentSpinning.new("a{}").to_source).to eq("a")
206
+ expect(ContentSpinning.new("a{|}").to_source).to eq("a")
207
+ expect(ContentSpinning.new("a{||}").to_source).to eq("a")
208
+ expect(ContentSpinning.new("{}a{}").to_source).to eq("a")
209
+ expect(ContentSpinning.new("{}a{|}").to_source).to eq("a")
210
+
211
+ expect(ContentSpinning.new("a{{}}").to_source).to eq("a")
212
+ expect(ContentSpinning.new("a{{|}}").to_source).to eq("a")
213
+ expect(ContentSpinning.new("a{{}|}").to_source).to eq("a")
214
+
215
+ expect(ContentSpinning.new("a{a{}}").to_source).to eq("aa")
216
+ end
217
+
218
+ it "removes spin with no choice" do
219
+ expect(ContentSpinning.new("{a}").to_source).to eq("a")
220
+ expect(ContentSpinning.new("a{b}").to_source).to eq("ab")
221
+ expect(ContentSpinning.new("a{b}c").to_source).to eq("abc")
222
+ expect(ContentSpinning.new("a{b}c{d}e").to_source).to eq("abcde")
223
+
224
+ expect(ContentSpinning.new("{{a}}").to_source).to eq("a")
225
+ expect(ContentSpinning.new("a{{b}}").to_source).to eq("ab")
226
+ expect(ContentSpinning.new("a{{b}}c").to_source).to eq("abc")
227
+ expect(ContentSpinning.new("a{{b}}c{{d}}e").to_source).to eq("abcde")
228
+
229
+ expect(ContentSpinning.new("{{{a}}}").to_source).to eq("a")
230
+ end
231
+
232
+ it "removes duplicate choices" do
233
+ expect(ContentSpinning.new("{a|a}").to_source).to eq("a")
234
+ expect(ContentSpinning.new("{a|a|b}").to_source).to eq("{a|b}")
235
+ expect(ContentSpinning.new("{a|b|a|b}").to_source).to eq("{a|b}")
236
+ end
237
+
238
+ it "keeps legitimate spin" do
239
+ expect(ContentSpinning.new("{a|b}").to_source).to eq("{a|b}")
240
+ expect(ContentSpinning.new("a{b|c}").to_source).to eq("a{b|c}")
241
+ expect(ContentSpinning.new("a{b|}").to_source).to eq("a{b|}")
242
+ expect(ContentSpinning.new("{{a|b}|c}").to_source).to eq("{{a|b}|c}")
243
+ end
142
244
  end
143
245
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: content_spinning
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxime Garcia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-15 00:00:00.000000000 Z
11
+ date: 2017-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -44,6 +44,9 @@ files:
44
44
  - README.md
45
45
  - lib/content_spinning.rb
46
46
  - lib/content_spinning/core_ext/string.rb
47
+ - lib/content_spinning/sentence.rb
48
+ - lib/content_spinning/spinner.rb
49
+ - lib/content_spinning/string.rb
47
50
  - lib/content_spinning/version.rb
48
51
  - spec/content_spinning/core_ext/string_spec.rb
49
52
  - spec/content_spinning_spec.rb
@@ -68,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
71
  version: 1.3.6
69
72
  requirements: []
70
73
  rubyforge_project:
71
- rubygems_version: 2.6.4
74
+ rubygems_version: 2.6.8
72
75
  signing_key:
73
76
  specification_version: 4
74
77
  summary: Content Spinning