content_spinning 0.0.1 → 0.0.2

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.
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