content_spinning 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +14 -2
- data/lib/content_spinning.rb +50 -35
- data/lib/content_spinning/version.rb +1 -1
- data/spec/content_spinning_spec.rb +152 -0
- data/spec/spec_helper.rb +8 -0
- metadata +30 -4
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Content Spinning
|
2
2
|
|
3
|
-
|
3
|
+
`ContentSpinning` is a ruby library made to spin some text.
|
4
|
+
It manages nested spinning.
|
4
5
|
|
5
6
|
## Example
|
6
7
|
|
@@ -13,7 +14,12 @@ ContentSpinning.spin "Hi {there|you}! I'm {efficient|productive}."
|
|
13
14
|
returns this array :
|
14
15
|
|
15
16
|
```ruby
|
16
|
-
[
|
17
|
+
[
|
18
|
+
"Hi there! I'm efficient.",
|
19
|
+
"Hi there! I'm productive.",
|
20
|
+
"Hi you! I'm efficient.",
|
21
|
+
"Hi you! I'm productive."
|
22
|
+
]
|
17
23
|
```
|
18
24
|
|
19
25
|
## Install
|
@@ -22,3 +28,9 @@ returns this array :
|
|
22
28
|
gem install content_spinning
|
23
29
|
```
|
24
30
|
|
31
|
+
## Todo
|
32
|
+
|
33
|
+
A few things to do :
|
34
|
+
|
35
|
+
* Executable
|
36
|
+
|
data/lib/content_spinning.rb
CHANGED
@@ -2,64 +2,79 @@ module ContentSpinning
|
|
2
2
|
class << self
|
3
3
|
|
4
4
|
def spin(text)
|
5
|
+
text = clean(text)
|
5
6
|
result = parse(text)
|
7
|
+
|
6
8
|
spin_all_level(result[:parsed], result[:max_level])
|
7
9
|
end
|
8
10
|
|
11
|
+
def clean(text)
|
12
|
+
begin
|
13
|
+
text_before_run = text.clone
|
14
|
+
|
15
|
+
# Strip empty spin
|
16
|
+
text.gsub!(/\{\|*\}/, '')
|
17
|
+
|
18
|
+
# Remove spin with only one choice
|
19
|
+
text.gsub!(/\{([^\{\}\|]+)\}/, '\1')
|
20
|
+
|
21
|
+
end while (text != text_before_run)
|
22
|
+
|
23
|
+
text
|
24
|
+
end
|
25
|
+
|
9
26
|
def parse(text, level = 1)
|
10
27
|
return {:parsed => text, :max_level => level - 1} unless text.include? "{"
|
11
28
|
|
12
|
-
text.gsub!(/\{\}/, '')
|
13
|
-
text.gsub!(/\{([^\{\}\|]+)\}/, '\1')
|
14
|
-
|
15
29
|
text.gsub!(/\{([^\{\}]+)\}/) do |match|
|
16
|
-
match.gsub!(/\{/, "__SPIN_BEGIN_
|
17
|
-
match.gsub!(/\}/, "__SPIN_END_
|
18
|
-
match.gsub!(/\|/, "__SPIN_OR_
|
30
|
+
match.gsub!(/\{/, "__SPIN_BEGIN_#{level}__")
|
31
|
+
match.gsub!(/\}/, "__SPIN_END_#{level}__")
|
32
|
+
match.gsub!(/\|/, "__SPIN_OR_#{level}__")
|
19
33
|
end
|
20
34
|
|
21
35
|
parse(text, level+1)
|
22
36
|
end
|
23
37
|
|
24
38
|
def spin_a_level(text_or_array, level)
|
25
|
-
|
26
|
-
|
27
|
-
spin_begin =
|
28
|
-
spin_end =
|
29
|
-
spin_or =
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
39
|
+
content_array = text_or_array.is_a?(Array) ? text_or_array : [text_or_array]
|
40
|
+
|
41
|
+
spin_begin = "__SPIN_BEGIN_#{level}__"
|
42
|
+
spin_end = "__SPIN_END_#{level}__"
|
43
|
+
spin_or = "__SPIN_OR_#{level}__"
|
44
|
+
|
45
|
+
content_array.map! do |text|
|
46
|
+
if text.include? spin_begin
|
47
|
+
# Spin a first one
|
48
|
+
before, vary, after = text.partition(Regexp.new(spin_begin + '.+?' + spin_end))
|
49
|
+
vary.gsub!(Regexp.union(spin_begin, spin_end), '')
|
50
|
+
|
51
|
+
varies = vary.split(Regexp.new(spin_or), -1)
|
52
|
+
varies.map! { |vary| before + vary + after }
|
53
|
+
|
54
|
+
# Continue spinning the level if there are other same level spin or just return
|
55
|
+
if after.include? spin_begin
|
56
|
+
spin_a_level(varies, level).flatten
|
57
|
+
else
|
58
|
+
varies
|
59
|
+
end
|
60
|
+
else
|
61
|
+
text
|
46
62
|
end
|
47
|
-
|
48
|
-
varies
|
49
63
|
end
|
50
64
|
|
51
|
-
|
65
|
+
content_array.flatten
|
52
66
|
end
|
53
67
|
|
54
68
|
def spin_all_level(text_or_array, from_level)
|
55
|
-
|
56
|
-
return text_or_array if from_level == 0
|
69
|
+
content_array = text_or_array.is_a?(Array) ? text_or_array : [text_or_array]
|
57
70
|
|
58
|
-
|
59
|
-
|
71
|
+
if from_level > 0
|
72
|
+
(1..from_level).reverse_each do |level|
|
73
|
+
content_array = spin_a_level(content_array, level)
|
74
|
+
end
|
60
75
|
end
|
61
76
|
|
62
|
-
|
77
|
+
content_array.delete_if(&:empty?).uniq
|
63
78
|
end
|
64
79
|
|
65
80
|
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# encoding: utf-8
|
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
|
17
|
+
|
18
|
+
describe ContentSpinning do
|
19
|
+
|
20
|
+
describe "clean" do
|
21
|
+
it "should return the string if there is no spin" do
|
22
|
+
ContentSpinning.clean("AaBb").should eq "AaBb"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should strip empty spin" do
|
26
|
+
ContentSpinning.clean("a{}").should eq "a"
|
27
|
+
ContentSpinning.clean("a{|}").should eq "a"
|
28
|
+
ContentSpinning.clean("a{||}").should eq "a"
|
29
|
+
ContentSpinning.clean("{}a{}").should eq "a"
|
30
|
+
ContentSpinning.clean("{}a{|}").should eq "a"
|
31
|
+
|
32
|
+
ContentSpinning.clean("a{{}}").should eq "a"
|
33
|
+
ContentSpinning.clean("a{{|}}").should eq "a"
|
34
|
+
ContentSpinning.clean("a{{}|}").should eq "a"
|
35
|
+
|
36
|
+
ContentSpinning.clean("a{a{}}").should eq "aa"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should remove spin with no choice" do
|
40
|
+
ContentSpinning.clean("{a}").should eq "a"
|
41
|
+
ContentSpinning.clean("a{b}").should eq "ab"
|
42
|
+
ContentSpinning.clean("a{b}c").should eq "abc"
|
43
|
+
ContentSpinning.clean("a{b}c{d}e").should eq "abcde"
|
44
|
+
|
45
|
+
ContentSpinning.clean("{{a}}").should eq "a"
|
46
|
+
ContentSpinning.clean("a{{b}}").should eq "ab"
|
47
|
+
ContentSpinning.clean("a{{b}}c").should eq "abc"
|
48
|
+
ContentSpinning.clean("a{{b}}c{{d}}e").should eq "abcde"
|
49
|
+
|
50
|
+
ContentSpinning.clean("{{{a}}}").should eq "a"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should keep legitimate spin" do
|
54
|
+
ContentSpinning.clean("{a|b}").should eq "{a|b}"
|
55
|
+
ContentSpinning.clean("a{b|c}").should eq "a{b|c}"
|
56
|
+
ContentSpinning.clean("{{a|b}|c}").should eq "{{a|b}|c}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "parse" do
|
61
|
+
it "should return the string if there is no spin" do
|
62
|
+
ContentSpinning.parse("AaBb").should eq :max_level => 0, :parsed => "AaBb"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should parse simple spin" do
|
66
|
+
ContentSpinning.parse("{a|b}").should eq :max_level => 1, :parsed => "__SPIN_BEGIN_1__a__SPIN_OR_1__b__SPIN_END_1__"
|
67
|
+
ContentSpinning.parse("a{b|c}").should eq :max_level => 1, :parsed => "a__SPIN_BEGIN_1__b__SPIN_OR_1__c__SPIN_END_1__"
|
68
|
+
ContentSpinning.parse("{a|b}c{d|e}").should 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
|
+
end
|
70
|
+
|
71
|
+
it "should manage recursive spin" do
|
72
|
+
ContentSpinning.parse("{{a|b}|c}").should 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__"
|
73
|
+
ContentSpinning.parse("{a|{b|c}}").should 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
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "spin" do
|
78
|
+
it "should call the clean function of ContentSpinning module with the string in argument" do
|
79
|
+
ContentSpinning.should_receive(:clean).with("AaBb").and_return("AaBb")
|
80
|
+
ContentSpinning.spin("AaBb")
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should return an array" do
|
84
|
+
"AaBb".spin.should eq ["AaBb"]
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should return an empty array if the string to spin is empty" do
|
88
|
+
"".spin.should eq []
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should strip empty choices" do
|
92
|
+
"a{}".spin.should eq ["a"]
|
93
|
+
"a{|}".spin.should eq ["a"]
|
94
|
+
"a{||}".spin.should eq ["a"]
|
95
|
+
"{}a{}".spin.should eq ["a"]
|
96
|
+
"{}a{|}".spin.should eq ["a"]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should strip empty strings from the returned array" do
|
100
|
+
"{|a}".spin.should eq ["a"]
|
101
|
+
"{a|}".spin.should eq ["a"]
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should manage one spin" do
|
105
|
+
"{a}".spin.should eq ["a"]
|
106
|
+
"a{b}".spin.should eq ["ab"]
|
107
|
+
"a{b}c".spin.should eq ["abc"]
|
108
|
+
"{a}{b}".spin.should eq ["ab"]
|
109
|
+
"a{b}{c}d".spin.should eq ["abcd"]
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should manage two spin" do
|
113
|
+
"{a}".spin.should eq ["a"]
|
114
|
+
"a{b}".spin.should eq ["ab"]
|
115
|
+
"a{b}c".spin.should eq ["abc"]
|
116
|
+
"{a}{b}".spin.should eq ["ab"]
|
117
|
+
"a{b}{c}d".spin.should eq ["abcd"]
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should manage spin with an empty choice" do
|
121
|
+
"{|a}".spin.should eq ["a"]
|
122
|
+
"{|a}b".spin.should eq ["b", "ab"]
|
123
|
+
"{a|}b".spin.should eq ["ab", "b"]
|
124
|
+
"{a|}{b|}".spin.should eq ["ab", "a", "b"]
|
125
|
+
"a{b|}{c|}d".spin.should eq ["abcd", "abd", "acd", "ad"]
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should manage spin with two choice" do
|
129
|
+
"{a|b}".spin.should eq ["a", "b"]
|
130
|
+
"{a|b}c".spin.should eq ["ac", "bc"]
|
131
|
+
"{a|b}{c|d}".spin.should eq ["ac", "ad", "bc", "bd"]
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should manage spin with three choice" do
|
135
|
+
"{a|b|c}".spin.should eq ["a", "b", "c"]
|
136
|
+
"{a|b|c}d".spin.should eq ["ad", "bd", "cd"]
|
137
|
+
"{a|b|c}{d|e}".spin.should eq ["ad", "ae", "bd", "be", "cd", "ce"]
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should manage recursive spin" do
|
141
|
+
"{a{b|c}|d}".spin.should eq ["ab", "ac", "d"]
|
142
|
+
"{{a|b}|c}".spin.should eq ["a", "b", "c"]
|
143
|
+
"{a|{b|c}}".spin.should eq ["a", "b", "c"]
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should not return twice the same result" do
|
147
|
+
"{a|a}".spin.should eq ["a"]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
data/spec/spec_helper.rb
ADDED
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.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,30 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
13
|
-
dependencies:
|
12
|
+
date: 2012-03-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &11429000 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.8'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *11429000
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: guard-rspec
|
27
|
+
requirement: &11428420 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *11428420
|
14
36
|
description: ! " To spin some text, mainly for SEO purpose.\n\n Spinning the
|
15
37
|
string \"Hi {there|you}! I'm {efficient|productive}.\" gives\n these four strings
|
16
38
|
:\n\n * Hi there! I'm efficient.\n * Hi there! I'm productive.\n * Hi you!
|
@@ -25,6 +47,8 @@ files:
|
|
25
47
|
- LICENSE
|
26
48
|
- lib/content_spinning/version.rb
|
27
49
|
- lib/content_spinning.rb
|
50
|
+
- spec/content_spinning_spec.rb
|
51
|
+
- spec/spec_helper.rb
|
28
52
|
homepage: http://github.com/maximeg/content_spinning
|
29
53
|
licenses: []
|
30
54
|
post_install_message:
|
@@ -49,4 +73,6 @@ rubygems_version: 1.8.15
|
|
49
73
|
signing_key:
|
50
74
|
specification_version: 3
|
51
75
|
summary: Content Spinning
|
52
|
-
test_files:
|
76
|
+
test_files:
|
77
|
+
- spec/content_spinning_spec.rb
|
78
|
+
- spec/spec_helper.rb
|