content_spinning 0.2.0 → 0.3.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/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
|