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 CHANGED
@@ -1,6 +1,7 @@
1
1
  # Content Spinning
2
2
 
3
- content_spinning is a ruby lib to spin some text.
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
- ["Hi there! I'm efficient.", "Hi there! I'm productive.", "Hi you! I'm efficient.", "Hi you! I'm productive."]
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
+
@@ -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_" + level.to_s + "__")
17
- match.gsub!(/\}/, "__SPIN_END_" + level.to_s + "__")
18
- match.gsub!(/\|/, "__SPIN_OR_" + level.to_s + "__")
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
- text_or_array = [text_or_array] unless text_or_array.is_a? Array
26
-
27
- spin_begin = '__SPIN_BEGIN_' + level.to_s + '__'
28
- spin_end = '__SPIN_END_' + level.to_s + '__'
29
- spin_or = '__SPIN_OR_' + level.to_s + '__'
30
-
31
- text_or_array.map! do |text|
32
- return [text] unless text.include? spin_begin
33
-
34
- array = text.partition(Regexp.new(spin_begin + '.+?' + spin_end))
35
- #puts array.inspect
36
-
37
- deb = array[0]
38
- fin = array[2]
39
-
40
- vary = array[1]
41
- vary.gsub!(Regexp.union(spin_begin, spin_end), '')
42
- varies = vary.split(Regexp.new(spin_or))
43
-
44
- varies.map! do |vary|
45
- spin_a_level([deb + vary + fin], level)
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
- text_or_array.flatten
65
+ content_array.flatten
52
66
  end
53
67
 
54
68
  def spin_all_level(text_or_array, from_level)
55
- text_or_array = [text_or_array] unless text_or_array.is_a? Array
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
- (1..from_level).reverse_each do |level|
59
- text_or_array = spin_a_level(text_or_array, level)
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
- text_or_array
77
+ content_array.delete_if(&:empty?).uniq
63
78
  end
64
79
 
65
80
  end
@@ -1,6 +1,6 @@
1
1
  module ContentSpinning
2
2
  module Version
3
- STRING = '0.0.1'
3
+ STRING = '0.0.2'
4
4
  end
5
5
  end
6
6
 
@@ -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
+
@@ -0,0 +1,8 @@
1
+ require 'rspec'
2
+ require 'content_spinning'
3
+
4
+ RSpec.configure do |config|
5
+ config.color_enabled = true
6
+ config.formatter = 'documentation'
7
+ end
8
+
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.1
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-02-29 00:00:00.000000000 Z
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