texttube 5.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +22 -0
- data/CHANGES.md +148 -0
- data/Gemfile +24 -0
- data/README.md +306 -0
- data/Rakefile +43 -0
- data/lib/ext/blank.rb +17 -0
- data/lib/ext/to_constant.rb +26 -0
- data/lib/texttube/base.rb +158 -0
- data/lib/texttube/filterable.rb +53 -0
- data/lib/texttube/filters/coderay.rb +68 -0
- data/lib/texttube/filters/embedding_audio.rb +61 -0
- data/lib/texttube/filters/embedding_video.rb +111 -0
- data/lib/texttube/filters/inside_block.rb +35 -0
- data/lib/texttube/filters/link_reffing.rb +144 -0
- data/lib/texttube/version.rb +6 -0
- data/lib/texttube.rb +23 -0
- data/spec/coderay_spec.rb +87 -0
- data/spec/embedding_audio_spec.rb +42 -0
- data/spec/inside_block_spec.rb +35 -0
- data/spec/link_reffing_spec.rb +97 -0
- data/spec/markdownfilters_spec.rb +280 -0
- data/spec/spec_helper.rb +33 -0
- data/texttube.gemspec +20 -0
- metadata +107 -0
data/.gitignore
ADDED
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[⁰](#0 "Jump to reference") is good. Erik Hollensbe's blog[¹](#1 "Jump to reference") is also good, as is James Coglan's blog[²](#2 "Jump to reference")\n<div markdown='1' id='reflinks'>\n<a name="0"></a>[0] [http://iainbarnett.me.uk](http://iainbarnett.me.uk "http://iainbarnett.me.uk") My blog\n\n\n<a name="1"></a>[1] [http://erik.hollensbe.org/](http://erik.hollensbe.org/ "http://erik.hollensbe.org/") Holistic Engineering\n\n\n<a name="2"></a>[2] [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">⁰</a> is good. Erik Hollensbe's blog<a href="#1" title="Jump to reference">¹</a> is also good, as is James Coglan's blog<a href="#2" title="Jump to reference">²</a></p>
|
148
|
+
|
149
|
+
<div markdown='1' id='reflinks'>
|
150
|
+
<a name="0"></a>[0] [http://iainbarnett.me.uk](http://iainbarnett.me.uk "http://iainbarnett.me.uk") My blog
|
151
|
+
|
152
|
+
|
153
|
+
<a name="1"></a>[1] [http://erik.hollensbe.org/](http://erik.hollensbe.org/ "http://erik.hollensbe.org/") Holistic Engineering
|
154
|
+
|
155
|
+
|
156
|
+
<a name="2"></a>[2] [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 << <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 << <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,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
|