texttube 5.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.old
2
+ *.tmproj
3
+ .DS_Store
4
+ .rvmrc
5
+
6
+ *.gem
7
+
8
+ *.7z
9
+ *.dmg
10
+ *.gz
11
+ *.iso
12
+ *.jar
13
+ *.rar
14
+ *.tar
15
+ *.zip
16
+ pkg
17
+ rdoc
18
+ .rspec
19
+ Gemfile.lock
20
+ bin/
21
+ vendor/
22
+ coverage/
data/CHANGES.md ADDED
@@ -0,0 +1,148 @@
1
+ # CH CH CH CHANGES! #
2
+
3
+ ## Thursday the 27th of June, 2013, v5.0.2 ##
4
+
5
+ * Renamed library.
6
+
7
+ ----
8
+
9
+
10
+ ## Monday the 10th of June, 2013 ##
11
+
12
+ ### v5.0.1 ###
13
+
14
+ * Improved spec for coderay scanner.
15
+
16
+ ----
17
+
18
+
19
+ ### v5.0.0 ###
20
+
21
+ * Completely changed the main interface. Now can take filters and run them in any order using a DSL.
22
+
23
+ ----
24
+
25
+
26
+ ## v4.0.0, Thursday the 6th of June, 2013 ##
27
+
28
+ * Cleaned up the link reffing code quite a bit. Can take options now to determine type of process (reference links or inline) and the format of the links (markdown, html).
29
+
30
+ ----
31
+
32
+
33
+ ## v3.0.0, Wednesday the 5th of June, 2013 ##
34
+
35
+ * Not using Hpricot anymore, I don't think it's being maintained. Moved to Nokogiri.
36
+ * Added more specs.
37
+ * Added much more docs. Got 100% coverage.
38
+
39
+ ----
40
+
41
+
42
+ ## v2.0.0, Tuesday the 4th of June, 2013 ##
43
+
44
+ * Added an abstract superclass so that filters can be sorted by type. Makes it easier to do things like "run all the before filters".
45
+ * Moved the filters to their own directory, just to be organised.
46
+
47
+ ----
48
+
49
+
50
+ ## v1.1.0, Monday the 3rd of June, 2013 ##
51
+
52
+ * Reorganised to use Simplecov, Yard etc.
53
+ * Instead of loading all the filters and have the client code then need a config to handle them, just set them up via requires in the client code.
54
+ * Fixed up the specs a bit.
55
+
56
+ ----
57
+
58
+
59
+ ## v1.0.5 ##
60
+
61
+ * Updated dependencies for coderay. Following minor versions up to 2.0.
62
+
63
+ ----
64
+
65
+
66
+ ## v1.0.4 ##
67
+
68
+ * Only follow patch upgrades to dependencies. Should cut out horrible errors down the line.
69
+
70
+ ----
71
+
72
+
73
+ ## v1.0.3 ##
74
+
75
+ * Bug fix
76
+
77
+ ----
78
+
79
+
80
+ ## v1.0.2 ##
81
+
82
+ * Using named html entities for some of the superscript numbers as some browsers aren't rendering the codes properly.
83
+
84
+ ----
85
+
86
+
87
+ ## v1.0.0 ##
88
+
89
+ * Added coderay filter
90
+
91
+ ----
92
+
93
+ ## v0.4.0 ##
94
+
95
+ * Made API more consistent and added more specs.
96
+
97
+ ----
98
+
99
+
100
+ ## v0.3.0 ##
101
+
102
+ * Source now supports ogg files in tandem with m4a, as a fallback for Firefox and other stuck up browsers.
103
+
104
+ ----
105
+
106
+
107
+ ## v0.2.0 ##
108
+
109
+ * Made audio able to take options, it's html5, and it has specs.
110
+
111
+ ----
112
+
113
+
114
+ ## v0.1.2 ##
115
+
116
+ * Bugfixes.
117
+
118
+ ----
119
+
120
+
121
+ ## v0.1.0 ##
122
+
123
+ * Added HTML5 audio tag support.
124
+
125
+ ----
126
+
127
+
128
+ ## v0.0.3 ##
129
+
130
+ * Added better div wrapper for links
131
+
132
+ ----
133
+
134
+
135
+ ## v0.0.2 ##
136
+
137
+ * Added filter for embedding video. Only Youtube for now.
138
+
139
+ ----
140
+
141
+
142
+ ## v0.0.1 ##
143
+
144
+ * Getting started!
145
+
146
+ ----
147
+
148
+
data/Gemfile ADDED
@@ -0,0 +1,24 @@
1
+ # A sample Gemfile
2
+ source "https://rubygems.org"
3
+
4
+ gemspec
5
+
6
+ gem "rake"
7
+
8
+ group :documentation do
9
+ gem "yard"
10
+ gem "rdiscount"
11
+ end
12
+
13
+ group :development do
14
+ gem "rdiscount"
15
+ gem "wirble"
16
+ end
17
+
18
+ group :test do
19
+ gem "rspec"
20
+ gem "simplecov", :require => false
21
+ gem "maruku"
22
+ gem "rdiscount"
23
+ gem "kramdown"
24
+ end
data/README.md ADDED
@@ -0,0 +1,306 @@
1
+ ## TextTube ##
2
+
3
+ Pass a string through filters to transform it.
4
+
5
+ ### Why? ###
6
+
7
+ I wanted to run a filter across articles I'd written for [my blog](http://iainbarnett.me.uk/), but also for the atom feed to the blog. Both needed some of the filters, but the atom feed needed less of them and slightly different options.
8
+
9
+
10
+ ### What does it do? ###
11
+
12
+ You want to filter/transform a string. You also want to run several filters across it, usually in the same way but sometimes just some of them, sometimes in a slightly different order. Object orientated programming will come to our rescue!
13
+
14
+ * The string is the instance.
15
+ * Modules hold groups of reusable filters.
16
+ * A class defines which filters to use.
17
+ * The method for running the filters will also allow ordering.
18
+
19
+ In practice this means:
20
+
21
+
22
+ require 'texttube/filterable'
23
+
24
+ module AFilter
25
+ extend TextTube::Filterable
26
+
27
+ filter_with :double do |text|
28
+ text * 2
29
+ end
30
+
31
+ filter_with :triple do |text|
32
+ text * 3
33
+ end
34
+ end
35
+
36
+ module BFil
37
+ extend TextTube::Filterable
38
+
39
+ filter_with :spacial do |current,options|
40
+ current.split(//).join " "
41
+ end
42
+ end
43
+
44
+ require 'texttube/base'
45
+
46
+ class NeuS < TextTube::Base
47
+ register BFil
48
+ register AFilter
49
+ register do # on the fly
50
+ filter_with :dashes do |text|
51
+ "---#{text}---"
52
+ end
53
+ end
54
+ end
55
+
56
+ Now there is a class `NeuS` which will run filters `:double`, `:triple` and `spacial` in that order, on a given string. For example:
57
+
58
+ n = NeuS.new "abc"
59
+
60
+ Running all of the filters:
61
+
62
+ n.filter
63
+ # => "---a b ca b ca b ca b ca b ca b c---"
64
+
65
+ Or just some of the filters:
66
+
67
+ n.filter :spacial
68
+ # => "a b c"
69
+ n.filter :spacial, :dashes
70
+ # => "---a b c---"
71
+
72
+ Run them more than once:
73
+
74
+ n.filter :double, :triple, :double
75
+ # => "abcabcabcabcabcabcabcabcabcabcabcabc"
76
+
77
+ ### Creating a filter ###
78
+
79
+ Make something _filterable_:
80
+
81
+ require 'texttube/filterable'
82
+
83
+ module AnotherFilter
84
+ extend TextTube::Filterable
85
+
86
+ filter_with :copyright do |text|
87
+ text << " ©#{Time.now.year}. "
88
+ end
89
+
90
+ filter_with :number do |text,options|
91
+ text * options[:times].to_i
92
+ end
93
+ end
94
+
95
+ That's all there is to creating a filter.
96
+
97
+ ### Creating a filter class ###
98
+
99
+ The class picks which filters to use, and can add filters on the fly, by using `register`:
100
+
101
+ require 'texttube/base'
102
+
103
+ class MyString < TextTube::Base
104
+ register AnotherFilter
105
+ register do
106
+ filter_with :my_name do |text|
107
+ text.gsub "Iain Barnett", %q!<a href="iainbarnett.me.uk" title="My blog">Iain Barnett</a>!
108
+ end
109
+ end
110
+ end
111
+
112
+ s = MyString.new "Let me introduce Iain Barnett. He writes Ruby code."
113
+ # => "Let me introduce Iain Barnett. He writes Ruby code."
114
+
115
+ MyString.options.merge! :number => {times: 2}
116
+ # => {:number=>{:times=>2}}
117
+
118
+ s.filter
119
+ # => "Let me introduce <a href="iainbarnett.me.uk" title="My blog">Iain Barnett</a>. He writes Ruby code. ©2013. Let me introduce <a href="iainbarnett.me.uk" title="My blog">Iain Barnett</a>. He writes Ruby code. ©2013. "
120
+
121
+
122
+ ## The Filters ##
123
+
124
+ Here are some ready built filters to use.
125
+
126
+ ### LinkReffing ###
127
+
128
+ If you'd don't want your links inline and would prefer to have them at the bottom of the document, then you can use this:
129
+
130
+ require 'texttube/base'
131
+ require 'texttube/filters/link_reffing'
132
+
133
+ class TextWithLinks < TextTube::Base
134
+ register TextTube::LinkReffing
135
+ end
136
+
137
+ s = TextWithLinks.new %q!Iain's blog[[http://iainbarnett.me.uk|My blog]] is good. Erik Hollensbe's blog[[http://erik.hollensbe.org/|Holistic Engineering]] is also good, as is James Coglan's blog[[http://blog.jcoglan.com/|The If Works]]!
138
+
139
+ s.filter
140
+
141
+ and it will produce this:
142
+
143
+ # => "Iain's blog[&#8304;](#0 "Jump to reference") is good. Erik Hollensbe's blog[&sup1;](#1 "Jump to reference") is also good, as is James Coglan's blog[&sup2;](#2 "Jump to reference")\n<div markdown='1' id='reflinks'>\n<a name="0"></a>&#91;0&#93; [http://iainbarnett.me.uk](http://iainbarnett.me.uk "http://iainbarnett.me.uk") My blog\n\n\n<a name="1"></a>&#91;1&#93; [http://erik.hollensbe.org/](http://erik.hollensbe.org/ "http://erik.hollensbe.org/") Holistic Engineering\n\n\n<a name="2"></a>&#91;2&#93; [http://blog.jcoglan.com/](http://blog.jcoglan.com/ "http://blog.jcoglan.com/") The If Works\n\n</div>"
144
+
145
+ Run that through a markdown parser and you get:
146
+
147
+ <p>Iain's blog<a href="#0" title="Jump to reference">&#8304;</a> is good. Erik Hollensbe's blog<a href="#1" title="Jump to reference">&sup1;</a> is also good, as is James Coglan's blog<a href="#2" title="Jump to reference">&sup2;</a></p>
148
+
149
+ <div markdown='1' id='reflinks'>
150
+ <a name="0"></a>&#91;0&#93; [http://iainbarnett.me.uk](http://iainbarnett.me.uk "http://iainbarnett.me.uk") My blog
151
+
152
+
153
+ <a name="1"></a>&#91;1&#93; [http://erik.hollensbe.org/](http://erik.hollensbe.org/ "http://erik.hollensbe.org/") Holistic Engineering
154
+
155
+
156
+ <a name="2"></a>&#91;2&#93; [http://blog.jcoglan.com/](http://blog.jcoglan.com/ "http://blog.jcoglan.com/") The If Works
157
+
158
+ </div>
159
+
160
+ Using this will probably end up with also using InsideBlock, to transform the markdown inside the div.
161
+
162
+ ### InsideBlock ###
163
+
164
+ Sometimes it'd be useful to wrap some markdown with HTML, for example:
165
+
166
+ <div id="notes">
167
+
168
+ * first
169
+ * second
170
+ * third
171
+
172
+ </div>
173
+
174
+ If you put this through a markdown parser the markdown won't get parsed:
175
+
176
+ require 'rdiscount'
177
+ s = "<div id="notes">\n\n* first\n* second\n* third\n\n</div>\n"
178
+ puts RDiscount.new(s).to_html
179
+
180
+ This is the output:
181
+
182
+ <div id="notes">
183
+
184
+ * first
185
+ * second
186
+ * third
187
+
188
+ </div>
189
+
190
+ My brilliant idea to get around this is to add an HTML attribute of `markdown='1'` to HTML tags that you want the markdown parser to look inside:
191
+
192
+ <div id="notes" markdown='1'>
193
+
194
+ * first
195
+ * second
196
+ * third
197
+
198
+ </div>
199
+
200
+ Trying this with `InsideBlock` gives:
201
+
202
+ puts TextTube::InsideBlock.run s
203
+
204
+ <div id="notes">
205
+ <ul>
206
+ <li>first</li>
207
+ <li>second</li>
208
+ <li>third</li>
209
+ </ul>
210
+
211
+ </div>
212
+
213
+ To use it as a filter:
214
+
215
+ require 'texttube/base'
216
+
217
+ class MyFilter < TextTube::Base
218
+ register TextTube::InsideBlock
219
+ end
220
+
221
+ myf = MyFilter.new(s)
222
+ # => "<div id="notes" markdown='1'>\n\n* first\n* second\n* third\n\n</div>\n"
223
+
224
+ puts myf.filter
225
+
226
+ Gives:
227
+
228
+ <div id="notes">
229
+ <ul>
230
+ <li>first</li>
231
+ <li>second</li>
232
+ <li>third</li>
233
+ </ul>
234
+
235
+ </div>
236
+
237
+ ### Coderay ###
238
+
239
+ Filters an HTML code block and marks it up with [coderay](http://coderay.rubychan.de/):
240
+
241
+
242
+
243
+ require 'texttube/base'
244
+ require 'texttube/filters/coderay'
245
+ require 'rdiscount' # a markdown parser
246
+
247
+ class TextWithCode < TextTube::Base
248
+ register do
249
+ filter_with :rdiscount do |text|
250
+ RDiscount.new(text).to_html
251
+ end
252
+ end
253
+ register TextTube::Coderay
254
+ end
255
+
256
+ s = TextWithCode.new <<'STR'
257
+ # FizzBuzz #
258
+
259
+ ::::ruby
260
+ (1..100).each do |n|
261
+ out = "#{n}: "
262
+ out << "Fizz" if n % 3 == 0
263
+ out << "Buzz" if n % 5 == 0
264
+ puts out
265
+ end
266
+
267
+ That's all folks!
268
+ STR
269
+ # => "# FizzBuzz #\n\n ::::ruby\n (1..100).each do |n| \n out = "\#{n}: "\n out << "Fizz" if n % 3 == 0\n out << "Buzz" if n % 5 == 0\n puts out\n end\n\nThat's all folks!\n"
270
+
271
+
272
+ puts s.filter
273
+
274
+ Produces:
275
+
276
+ <h1>FizzBuzz</h1>
277
+
278
+ <pre><code class="CodeRay">(<span class="integer">1</span>..<span class="integer">100</span>).each <span class="keyword">do</span> |n|
279
+ out = <span class="string"><span class="delimiter">"</span><span class="inline"><span class="inline-delimiter">#{</span>n<span class="inline-delimiter">}</span></span><span class="content">: </span><span class="delimiter">"</span></span>
280
+ out &lt;&lt; <span class="string"><span class="delimiter">"</span><span class="content">Fizz</span><span class="delimiter">"</span></span> <span class="keyword">if</span> n % <span class="integer">3</span> == <span class="integer">0</span>
281
+ out &lt;&lt; <span class="string"><span class="delimiter">"</span><span class="content">Buzz</span><span class="delimiter">"</span></span> <span class="keyword">if</span> n % <span class="integer">5</span> == <span class="integer">0</span>
282
+ puts out
283
+ <span class="keyword">end</span></code></pre>
284
+
285
+ <p>That's all folks!</p>
286
+
287
+ The language was specified with a leading `::::ruby`. It didn't have to be as the default is to use Ruby, but if you want to use any other of the [coderay supported languages](http://coderay.rubychan.de/doc/CodeRay/Scanners.html), that's how to do it.
288
+
289
+ ### Contributors ###
290
+
291
+ Many thanks to Eleni Karinou and [Annette Smith](https://twitter.com/moosecatear) for brainsplatting a new name for the library, and after many unusable and clearly disturbing suggestions, to Annette for the final name (and its future spin off, which will remain secret for now).
292
+
293
+ ### Licence ###
294
+
295
+ Copyright (c) 2013 Iain Barnett
296
+
297
+ MIT Licence
298
+
299
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
300
+
301
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
302
+
303
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
304
+
305
+
306
+ i.e. be good
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ # encoding: UTF-8
2
+
3
+ desc "(Re-) generate documentation and place it in the docs/ dir."
4
+ task :docs => :"docs:yard"
5
+ namespace :docs do
6
+ require 'yard'
7
+ YARD::Rake::YardocTask.new do |t|
8
+ t.files = ['lib/**/*.rb']
9
+ t.options = ['-odocs/', '--no-private']
10
+ end
11
+
12
+ desc "Docs including private methods."
13
+ YARD::Rake::YardocTask.new(:all) do |t|
14
+ t.files = ['lib/**/*.rb']
15
+ t.options = ['-odocs/']
16
+ end
17
+
18
+ desc "How to use the docs."
19
+ task :usage do
20
+ puts "Open the index.html file in the docs directory to read them. Does not include methods marked private unless you ran the 'all' version (you'll only need these if you plan to hack on the library itself)."
21
+ end
22
+ end
23
+
24
+
25
+ task :default => "spec"
26
+
27
+ task :spec => :"spec:run"
28
+ task :rspec => :spec
29
+ namespace :spec do
30
+ task :environment do
31
+ ENV["RACK_ENV"] = "test"
32
+ end
33
+
34
+ desc "Run specs"
35
+ task :run, [:any_args] => :"spec:environment" do |t,args|
36
+ warn "Entering spec task."
37
+ any_args = args[:any_args] || ""
38
+ cmd = "bin/rspec #{any_args}"
39
+ warn cmd
40
+ system cmd
41
+ end
42
+
43
+ end
data/lib/ext/blank.rb ADDED
@@ -0,0 +1,17 @@
1
+ # encoding: UTF-8
2
+
3
+ module TextTube
4
+ module CoreExtensions
5
+
6
+ def blank?
7
+ respond_to?(:empty?) ?
8
+ empty? :
9
+ !self
10
+ end
11
+ end
12
+ end
13
+
14
+ # Standard lib class.
15
+ class Hash
16
+ include TextTube::CoreExtensions
17
+ end
@@ -0,0 +1,26 @@
1
+ module TextTube
2
+
3
+ # Core lib extensions reside here.
4
+ module CoreExtensions
5
+ # to_constant tries to find a declared constant with the name specified
6
+ # in the string. It raises a NameError when the name is not in CamelCase
7
+ # or is not initialized.
8
+ #
9
+ # Examples
10
+ # "Module".to_constant #=> Module
11
+ # "Class".to_constant #=> Class
12
+ def to_constant
13
+ unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
14
+ fail NameError, "#{self.inspect} is not a valid constant name!"
15
+ end
16
+
17
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
18
+ end
19
+ end
20
+ end
21
+
22
+
23
+ # Standard lib String class gets some extras.
24
+ class String
25
+ include TextTube::CoreExtensions
26
+ end