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 +4 -4
- data/README.md +51 -1
- data/lib/content_spinning.rb +64 -93
- data/lib/content_spinning/core_ext/string.rb +2 -2
- data/lib/content_spinning/sentence.rb +58 -0
- data/lib/content_spinning/spinner.rb +43 -0
- data/lib/content_spinning/string.rb +35 -0
- data/lib/content_spinning/version.rb +2 -2
- data/spec/content_spinning/core_ext/string_spec.rb +1 -1
- data/spec/content_spinning_spec.rb +149 -47
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 725d38ecb0875c5f125823a80e16105d65875327
|
4
|
+
data.tar.gz: feaff568e498f301547e05d5472e7ff4dd9ea4f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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 :
|
data/lib/content_spinning.rb
CHANGED
@@ -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
|
-
|
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(
|
16
|
-
|
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
|
-
|
31
|
-
ONE_CHOICE_SPIN_REGEXP = /\{([^\{\}\|]+)\}/
|
32
|
-
|
33
|
-
def clean(text)
|
34
|
-
cleaned = text.dup
|
14
|
+
end
|
35
15
|
|
36
|
-
|
37
|
-
|
16
|
+
def initialize(source)
|
17
|
+
@source = source
|
18
|
+
end
|
38
19
|
|
39
|
-
|
40
|
-
cleaned.gsub!(EMPTY_SPIN_REGEXP, "")
|
20
|
+
attr_reader :source
|
41
21
|
|
42
|
-
|
43
|
-
|
22
|
+
def count
|
23
|
+
parse.count
|
24
|
+
end
|
44
25
|
|
45
|
-
|
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
|
-
|
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
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
-
|
91
|
-
|
92
|
-
|
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
|
-
|
109
|
-
|
110
|
-
end
|
75
|
+
def spin_with_limit(limit:)
|
76
|
+
parsed = parse
|
111
77
|
|
112
|
-
|
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
|
@@ -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
|
@@ -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
|
-
|
5
|
-
|
6
|
-
|
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 "
|
10
|
-
expect(ContentSpinning.
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
expect(ContentSpinning.
|
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
|
-
|
17
|
-
expect(ContentSpinning.
|
18
|
-
expect(ContentSpinning.
|
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
|
-
|
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 "
|
24
|
-
expect(ContentSpinning.
|
25
|
-
expect(ContentSpinning.
|
26
|
-
expect(ContentSpinning.
|
27
|
-
|
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
|
-
|
30
|
-
expect(ContentSpinning.
|
31
|
-
expect(ContentSpinning.
|
32
|
-
expect(ContentSpinning.
|
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
|
-
|
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 "
|
38
|
-
expect(ContentSpinning.
|
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.
|
77
|
+
expect(ContentSpinning.new("AaBb").parse).to eq("AaBb")
|
48
78
|
end
|
49
79
|
|
50
80
|
it "parses simple spin" do
|
51
|
-
expect(ContentSpinning.
|
52
|
-
|
53
|
-
|
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.
|
58
|
-
|
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 "
|
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 "
|
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 "
|
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.
|
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:
|
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.
|
74
|
+
rubygems_version: 2.6.8
|
72
75
|
signing_key:
|
73
76
|
specification_version: 4
|
74
77
|
summary: Content Spinning
|