content_spinning 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/content_spinning/core_ext/string.rb +7 -0
- data/lib/content_spinning/version.rb +5 -2
- data/lib/content_spinning.rb +16 -17
- data/spec/content_spinning/core_ext/string_spec.rb +21 -0
- data/spec/content_spinning_spec.rb +93 -104
- data/spec/spec_helper.rb +3 -6
- metadata +33 -33
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 79295ec814e234e885f05f6a026177cc49384acf
|
4
|
+
data.tar.gz: b0cee4376b527d0b7a1d1ef0373ff51e385fb8b4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3b44c72fddeafdd9fda092eb44c38f2a30547f974be9771ebf7fe2e92085ebdaaf6ba25991ce213bd4eb1e1c9db4f619d787ff5986b9e2b26528fce5dd5b0381
|
7
|
+
data.tar.gz: 22b09a4e78ccc4686a9387fe5b4313f35abf5d92bf7fe8ff490b2d6569424db83dac152770d66f05c7719ad518a027fc846bd10df7006656abad6e54787036bf
|
data/lib/content_spinning.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
require "content_spinning/core_ext/string"
|
2
|
+
|
1
3
|
module ContentSpinning
|
4
|
+
|
2
5
|
class << self
|
3
6
|
|
4
7
|
def spin(text)
|
8
|
+
text = text.dup
|
5
9
|
text = clean(text)
|
6
10
|
result = parse(text)
|
7
11
|
|
@@ -9,22 +13,23 @@ module ContentSpinning
|
|
9
13
|
end
|
10
14
|
|
11
15
|
def clean(text)
|
12
|
-
|
13
|
-
text_before_run = text.
|
16
|
+
loop do
|
17
|
+
text_before_run = text.dup
|
14
18
|
|
15
19
|
# Strip empty spin
|
16
|
-
text.gsub!(/\{\|*\}/,
|
20
|
+
text.gsub!(/\{\|*\}/, "")
|
17
21
|
|
18
22
|
# Remove spin with only one choice
|
19
23
|
text.gsub!(/\{([^\{\}\|]+)\}/, '\1')
|
20
24
|
|
21
|
-
|
25
|
+
break if text == text_before_run
|
26
|
+
end
|
22
27
|
|
23
28
|
text
|
24
29
|
end
|
25
30
|
|
26
31
|
def parse(text, level = 1)
|
27
|
-
return {:
|
32
|
+
return { parsed: text, max_level: level - 1 } unless text.include?("{")
|
28
33
|
|
29
34
|
text.gsub!(/\{([^\{\}]+)\}/) do |match|
|
30
35
|
match.gsub!(/\{/, "__SPIN_BEGIN_#{level}__")
|
@@ -32,7 +37,7 @@ module ContentSpinning
|
|
32
37
|
match.gsub!(/\|/, "__SPIN_OR_#{level}__")
|
33
38
|
end
|
34
39
|
|
35
|
-
parse(text, level+1)
|
40
|
+
parse(text, level + 1)
|
36
41
|
end
|
37
42
|
|
38
43
|
def spin_a_level(text_or_array, level)
|
@@ -43,16 +48,16 @@ module ContentSpinning
|
|
43
48
|
spin_or = "__SPIN_OR_#{level}__"
|
44
49
|
|
45
50
|
content_array.map! do |text|
|
46
|
-
if text.include?
|
51
|
+
if text.include?(spin_begin)
|
47
52
|
# Spin a first one
|
48
|
-
before, vary, after = text.partition(Regexp.new(spin_begin +
|
49
|
-
vary.gsub!(Regexp.union(spin_begin, spin_end),
|
53
|
+
before, vary, after = text.partition(Regexp.new(spin_begin + ".+?" + spin_end))
|
54
|
+
vary.gsub!(Regexp.union(spin_begin, spin_end), "")
|
50
55
|
|
51
56
|
varies = vary.split(Regexp.new(spin_or), -1)
|
52
|
-
varies.map! { |
|
57
|
+
varies.map! { |choice| before + choice + after }
|
53
58
|
|
54
59
|
# Continue spinning the level if there are other same level spin or just return
|
55
|
-
if after.include?
|
60
|
+
if after.include?(spin_begin)
|
56
61
|
spin_a_level(varies, level).flatten
|
57
62
|
else
|
58
63
|
varies
|
@@ -78,11 +83,5 @@ module ContentSpinning
|
|
78
83
|
end
|
79
84
|
|
80
85
|
end
|
81
|
-
end
|
82
86
|
|
83
|
-
String.class_eval do
|
84
|
-
def spin
|
85
|
-
ContentSpinning.spin(self)
|
86
|
-
end
|
87
87
|
end
|
88
|
-
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe String do
|
4
|
+
describe "#spin" do
|
5
|
+
it "is defined" do
|
6
|
+
expect("").to respond_to(:spin)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "calls the spin function of ContentSpinning module with the string in argument" do
|
10
|
+
expect(ContentSpinning).to receive(:spin).with("AaBb")
|
11
|
+
"AaBb".spin
|
12
|
+
end
|
13
|
+
|
14
|
+
it "does not modify the source string" do
|
15
|
+
source = "{a|b}"
|
16
|
+
expect {
|
17
|
+
source.spin
|
18
|
+
}.not_to change { source }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,152 +1,141 @@
|
|
1
|
-
|
2
|
-
require 'spec_helper'
|
3
|
-
|
4
|
-
describe String do
|
5
|
-
|
6
|
-
describe "spin" do
|
7
|
-
it "should be defined" do
|
8
|
-
String.new.respond_to?(:spin).should be_true
|
9
|
-
end
|
10
|
-
it "should call the spin function of ContentSpinning module with the string in argument" do
|
11
|
-
ContentSpinning.should_receive(:spin).with("AaBb")
|
12
|
-
"AaBb".spin
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
1
|
+
require "spec_helper"
|
17
2
|
|
18
3
|
describe ContentSpinning do
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
ContentSpinning.clean("AaBb").should eq "AaBb"
|
4
|
+
describe "#clean" do
|
5
|
+
it "returns the string if there is no spin" do
|
6
|
+
expect(ContentSpinning.clean("AaBb")).to eq("AaBb")
|
23
7
|
end
|
24
8
|
|
25
|
-
it "
|
26
|
-
ContentSpinning.clean("a{}").
|
27
|
-
ContentSpinning.clean("a{|}").
|
28
|
-
ContentSpinning.clean("a{||}").
|
29
|
-
ContentSpinning.clean("{}a{}").
|
30
|
-
ContentSpinning.clean("{}a{|}").
|
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")
|
31
15
|
|
32
|
-
ContentSpinning.clean("a{{}}").
|
33
|
-
ContentSpinning.clean("a{{|}}").
|
34
|
-
ContentSpinning.clean("a{{}|}").
|
16
|
+
expect(ContentSpinning.clean("a{{}}")).to eq("a")
|
17
|
+
expect(ContentSpinning.clean("a{{|}}")).to eq("a")
|
18
|
+
expect(ContentSpinning.clean("a{{}|}")).to eq("a")
|
35
19
|
|
36
|
-
ContentSpinning.clean("a{a{}}").
|
20
|
+
expect(ContentSpinning.clean("a{a{}}")).to eq("aa")
|
37
21
|
end
|
38
22
|
|
39
|
-
it "
|
40
|
-
ContentSpinning.clean("{a}").
|
41
|
-
ContentSpinning.clean("a{b}").
|
42
|
-
ContentSpinning.clean("a{b}c").
|
43
|
-
ContentSpinning.clean("a{b}c{d}e").
|
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")
|
44
28
|
|
45
|
-
ContentSpinning.clean("{{a}}").
|
46
|
-
ContentSpinning.clean("a{{b}}").
|
47
|
-
ContentSpinning.clean("a{{b}}c").
|
48
|
-
ContentSpinning.clean("a{{b}}c{{d}}e").
|
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")
|
49
33
|
|
50
|
-
ContentSpinning.clean("{{{a}}}").
|
34
|
+
expect(ContentSpinning.clean("{{{a}}}")).to eq("a")
|
51
35
|
end
|
52
36
|
|
53
|
-
it "
|
54
|
-
ContentSpinning.clean("{a|b}").
|
55
|
-
ContentSpinning.clean("a{b|c}").
|
56
|
-
ContentSpinning.clean("{{a|b}|c}").
|
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}|c}")).to eq("{{a|b}|c}")
|
57
41
|
end
|
58
42
|
end
|
59
43
|
|
60
|
-
describe "parse" do
|
61
|
-
it "
|
62
|
-
ContentSpinning.parse("AaBb").
|
44
|
+
describe "#parse" do
|
45
|
+
it "returns the string if there is no spin" do
|
46
|
+
expect(ContentSpinning.parse("AaBb")).to eq(max_level: 0, parsed: "AaBb")
|
63
47
|
end
|
64
48
|
|
65
|
-
it "
|
66
|
-
ContentSpinning.parse("{a|b}").
|
67
|
-
ContentSpinning.parse("a{b|c}").
|
68
|
-
ContentSpinning.parse("{a|b}c{d|e}").
|
49
|
+
it "parses simple spin" do
|
50
|
+
expect(ContentSpinning.parse("{a|b}")).to eq(max_level: 1, parsed: "__SPIN_BEGIN_1__a__SPIN_OR_1__b__SPIN_END_1__")
|
51
|
+
expect(ContentSpinning.parse("a{b|c}")).to eq(max_level: 1, parsed: "a__SPIN_BEGIN_1__b__SPIN_OR_1__c__SPIN_END_1__")
|
52
|
+
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__")
|
69
53
|
end
|
70
54
|
|
71
|
-
it "
|
72
|
-
ContentSpinning.parse("{{a|b}|c}").
|
73
|
-
ContentSpinning.parse("{a|{b|c}}").
|
55
|
+
it "manages recursive spin" do
|
56
|
+
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__")
|
57
|
+
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__")
|
74
58
|
end
|
75
59
|
end
|
76
60
|
|
77
|
-
describe "spin" do
|
78
|
-
it "
|
79
|
-
ContentSpinning.
|
61
|
+
describe "#spin" do
|
62
|
+
it "calls the clean function of ContentSpinning module with the string in argument" do
|
63
|
+
expect(ContentSpinning).to receive(:clean).with("AaBb").and_return("AaBb")
|
80
64
|
ContentSpinning.spin("AaBb")
|
81
65
|
end
|
82
66
|
|
83
|
-
it "
|
84
|
-
"AaBb".
|
67
|
+
it "returns an array" do
|
68
|
+
expect(ContentSpinning.spin("AaBb")).to eq(["AaBb"])
|
85
69
|
end
|
86
70
|
|
87
|
-
it "
|
88
|
-
"".
|
71
|
+
it "returns an empty array if the string to spin is empty" do
|
72
|
+
expect(ContentSpinning.spin("")).to eq([])
|
89
73
|
end
|
90
74
|
|
91
|
-
it "
|
92
|
-
"a{}".
|
93
|
-
"a{|}".
|
94
|
-
"a{||}".
|
95
|
-
"{}a{}".
|
96
|
-
"{}a{|}".
|
75
|
+
it "strips empty choices" do
|
76
|
+
expect(ContentSpinning.spin("a{}")).to eq(["a"])
|
77
|
+
expect(ContentSpinning.spin("a{|}")).to eq(["a"])
|
78
|
+
expect(ContentSpinning.spin("a{||}")).to eq(["a"])
|
79
|
+
expect(ContentSpinning.spin("{}a{}")).to eq(["a"])
|
80
|
+
expect(ContentSpinning.spin("{}a{|}")).to eq(["a"])
|
97
81
|
end
|
98
82
|
|
99
|
-
it "
|
100
|
-
"{|a}".
|
101
|
-
"{a|}".
|
83
|
+
it "strips empty strings from the returned array" do
|
84
|
+
expect(ContentSpinning.spin("{|a}")).to eq(["a"])
|
85
|
+
expect(ContentSpinning.spin("{a|}")).to eq(["a"])
|
102
86
|
end
|
103
87
|
|
104
|
-
it "
|
105
|
-
"{a}".
|
106
|
-
"a{b}".
|
107
|
-
"a{b}c".
|
108
|
-
"{a}{b}".
|
109
|
-
"a{b}{c}d".
|
88
|
+
it "manages one spin" do
|
89
|
+
expect(ContentSpinning.spin("{a}")).to eq(["a"])
|
90
|
+
expect(ContentSpinning.spin("a{b}")).to eq(["ab"])
|
91
|
+
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"])
|
110
94
|
end
|
111
95
|
|
112
|
-
it "
|
113
|
-
"{a}".
|
114
|
-
"a{b}".
|
115
|
-
"a{b}c".
|
116
|
-
"{a}{b}".
|
117
|
-
"a{b}{c}d".
|
96
|
+
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
|
+
expect(ContentSpinning.spin("{a}{b}")).to eq(["ab"])
|
101
|
+
expect(ContentSpinning.spin("a{b}{c}d")).to eq(["abcd"])
|
118
102
|
end
|
119
103
|
|
120
|
-
it "
|
121
|
-
"{|a}".
|
122
|
-
"{|a}b".
|
123
|
-
"{a|}b".
|
124
|
-
"{a|}{b|}".
|
125
|
-
"a{b|}{c|}d".
|
104
|
+
it "manages spin with an empty choice" do
|
105
|
+
expect(ContentSpinning.spin("{|a}")).to eq(["a"])
|
106
|
+
expect(ContentSpinning.spin("{|a}b")).to eq(%w(b ab))
|
107
|
+
expect(ContentSpinning.spin("{a|}b")).to eq(%w(ab b))
|
108
|
+
expect(ContentSpinning.spin("{a|}{b|}")).to eq(%w(ab a b))
|
109
|
+
expect(ContentSpinning.spin("a{b|}{c|}d")).to eq(%w(abcd abd acd ad))
|
126
110
|
end
|
127
111
|
|
128
|
-
it "
|
129
|
-
"{a|b}".
|
130
|
-
"{a|b}c".
|
131
|
-
"{a|b}{c|d}".
|
112
|
+
it "manages spin with two choice" do
|
113
|
+
expect(ContentSpinning.spin("{a|b}")).to eq(%w(a b))
|
114
|
+
expect(ContentSpinning.spin("{a|b}c")).to eq(%w(ac bc))
|
115
|
+
expect(ContentSpinning.spin("{a|b}{c|d}")).to eq(%w(ac ad bc bd))
|
132
116
|
end
|
133
117
|
|
134
|
-
it "
|
135
|
-
"{a|b|c}".
|
136
|
-
"{a|b|c}d".
|
137
|
-
"{a|b|c}{d|e}".
|
118
|
+
it "manages spin with three choice" do
|
119
|
+
expect(ContentSpinning.spin("{a|b|c}")).to eq(%w(a b c))
|
120
|
+
expect(ContentSpinning.spin("{a|b|c}d")).to eq(%w(ad bd cd))
|
121
|
+
expect(ContentSpinning.spin("{a|b|c}{d|e}")).to eq(%w(ad ae bd be cd ce))
|
138
122
|
end
|
139
123
|
|
140
|
-
it "
|
141
|
-
"{a{b|c}|d}".
|
142
|
-
"{{a|b}|c}".
|
143
|
-
"{a|{b|c}}".
|
124
|
+
it "manages recursive spin" do
|
125
|
+
expect(ContentSpinning.spin("{a{b|c}|d}")).to eq(%w(ab ac d))
|
126
|
+
expect(ContentSpinning.spin("{{a|b}|c}")).to eq(%w(a b c))
|
127
|
+
expect(ContentSpinning.spin("{a|{b|c}}")).to eq(%w(a b c))
|
144
128
|
end
|
145
129
|
|
146
|
-
it "
|
147
|
-
"{a|a}".
|
130
|
+
it "does not return twice the same result" do
|
131
|
+
expect(ContentSpinning.spin("{a|a}")).to eq(["a"])
|
148
132
|
end
|
149
|
-
end
|
150
133
|
|
134
|
+
it "does not modify the source string" do
|
135
|
+
source = "{a|b}"
|
136
|
+
expect {
|
137
|
+
ContentSpinning.spin(source)
|
138
|
+
}.not_to change { source }
|
139
|
+
end
|
140
|
+
end
|
151
141
|
end
|
152
|
-
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,78 +1,78 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: content_spinning
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Maxime Garcia
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2016-05-15 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rspec
|
16
|
-
requirement:
|
17
|
-
none: false
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
19
|
+
version: '3.4'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: guard-rspec
|
27
|
-
requirement: &11428420 !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
23
|
requirements:
|
30
|
-
- -
|
24
|
+
- - "~>"
|
31
25
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
26
|
+
version: '3.4'
|
27
|
+
description: |
|
28
|
+
To spin some text, mainly for SEO purpose.
|
29
|
+
|
30
|
+
Spinning the string "Hi {there|you}! I'm {efficient|productive}." gives
|
31
|
+
these four strings :
|
32
|
+
|
33
|
+
* Hi there! I'm efficient.
|
34
|
+
* Hi there! I'm productive.
|
35
|
+
* Hi you! I'm efficient.
|
36
|
+
* Hi you! I'm productive.
|
40
37
|
email:
|
41
|
-
- maxime.garcia@
|
38
|
+
- maxime.garcia@gmail.com
|
42
39
|
executables: []
|
43
40
|
extensions: []
|
44
41
|
extra_rdoc_files: []
|
45
42
|
files:
|
46
|
-
- README.md
|
47
43
|
- LICENSE
|
48
|
-
-
|
44
|
+
- README.md
|
49
45
|
- lib/content_spinning.rb
|
46
|
+
- lib/content_spinning/core_ext/string.rb
|
47
|
+
- lib/content_spinning/version.rb
|
48
|
+
- spec/content_spinning/core_ext/string_spec.rb
|
50
49
|
- spec/content_spinning_spec.rb
|
51
50
|
- spec/spec_helper.rb
|
52
51
|
homepage: http://github.com/maximeg/content_spinning
|
53
|
-
licenses:
|
52
|
+
licenses:
|
53
|
+
- MIT
|
54
|
+
metadata: {}
|
54
55
|
post_install_message:
|
55
56
|
rdoc_options: []
|
56
57
|
require_paths:
|
57
58
|
- lib
|
58
59
|
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
-
none: false
|
60
60
|
requirements:
|
61
|
-
- -
|
61
|
+
- - ">="
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: '
|
63
|
+
version: '1.9'
|
64
64
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
65
|
requirements:
|
67
|
-
- -
|
66
|
+
- - ">="
|
68
67
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
68
|
+
version: 1.3.6
|
70
69
|
requirements: []
|
71
70
|
rubyforge_project:
|
72
|
-
rubygems_version:
|
71
|
+
rubygems_version: 2.6.4
|
73
72
|
signing_key:
|
74
|
-
specification_version:
|
73
|
+
specification_version: 4
|
75
74
|
summary: Content Spinning
|
76
75
|
test_files:
|
76
|
+
- spec/content_spinning/core_ext/string_spec.rb
|
77
77
|
- spec/content_spinning_spec.rb
|
78
78
|
- spec/spec_helper.rb
|