cheat 1.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/LICENSE +18 -0
- data/README +16 -0
- data/bin/cheat +4 -0
- data/lib/cheat.rb +70 -0
- data/lib/site.rb +512 -0
- data/lib/wrap.rb +42 -0
- data/test/test_cheat.rb +50 -0
- metadata +53 -0
data/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2006 Chris Wanstrath
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
== Cheat
|
2
|
+
|
3
|
+
Cheat is a simple command line reference utility. Use it to retrieve handy
|
4
|
+
information from the cheat sheet repository.
|
5
|
+
|
6
|
+
$ cheat sheets
|
7
|
+
$ cheat cheat
|
8
|
+
$ cheat recent
|
9
|
+
|
10
|
+
The Cheat Sheet Repository:
|
11
|
+
- http://cheat.errtheblog.com/
|
12
|
+
|
13
|
+
Enjoy.
|
14
|
+
|
15
|
+
>> Chris Wanstrath
|
16
|
+
=> chris[at]ozmm[dot]org
|
data/bin/cheat
ADDED
data/lib/cheat.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
%w[rubygems fileutils net/http yaml open-uri wrap].each { |f| require f }
|
3
|
+
|
4
|
+
module Cheat
|
5
|
+
extend self
|
6
|
+
|
7
|
+
HOST = 'cheat.errtheblog.com'
|
8
|
+
PORT = 80
|
9
|
+
SUFFIX = ''
|
10
|
+
|
11
|
+
def sheets(args)
|
12
|
+
args = args.dup
|
13
|
+
|
14
|
+
return puts("Looking for help? Try http://cheat.errtheblog.com or `$ cheat cheat'") if args.empty?
|
15
|
+
|
16
|
+
if (i = args.index('--clear-cache') || i = args.index('--new'))
|
17
|
+
args.delete_at(i)
|
18
|
+
clear_cache
|
19
|
+
return if args.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
sheet = args.shift
|
23
|
+
|
24
|
+
cache_file = "#{cache_dir}/#{sheet}.yml" if cache_dir
|
25
|
+
FileUtils.mkdir(cache_dir) unless File.exists?(cache_dir) if cache_dir
|
26
|
+
|
27
|
+
host = HOST + ':' + PORT.to_s + SUFFIX
|
28
|
+
uri = "http://#{host}/y/"
|
29
|
+
|
30
|
+
if %w[sheets all recent].include? sheet
|
31
|
+
uri = uri.sub('/y/', sheet == 'recent' ? '/yr/' : '/ya/')
|
32
|
+
return open(uri) { |body| show(body.read) }
|
33
|
+
end
|
34
|
+
|
35
|
+
return show(File.read(cache_file)) if File.exists?(cache_file) rescue clear_cache if cache_file
|
36
|
+
|
37
|
+
open(uri += sheet) do |body|
|
38
|
+
sheet = body.read
|
39
|
+
File.open(cache_file, 'w') { |f| f.write(sheet) } if cache_file
|
40
|
+
show(sheet)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def show(sheet_yaml)
|
45
|
+
sheet = YAML.load(sheet_yaml).to_a.first
|
46
|
+
sheet[-1] = sheet.last.join("\n") if sheet[-1].is_a?(Array)
|
47
|
+
puts sheet.first + ':'
|
48
|
+
puts ' ' + sheet.last.gsub("\r",'').gsub("\n", "\n ").wrap(80)
|
49
|
+
end
|
50
|
+
|
51
|
+
def cache_dir
|
52
|
+
PLATFORM =~ /win32/ ? win32_cache_dir : File.join(File.expand_path("~"), ".cheat")
|
53
|
+
end
|
54
|
+
|
55
|
+
def win32_cache_dir
|
56
|
+
unless File.exists?(home = ENV['HOMEDRIVE'] + ENV['HOMEPATH'])
|
57
|
+
puts "No HOMEDRIVE or HOMEPATH environment variable. Set one to save a" +
|
58
|
+
"local cache of cheat sheets."
|
59
|
+
return false
|
60
|
+
else
|
61
|
+
return File.join(home, 'Cheat')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def clear_cache
|
66
|
+
FileUtils.rm_rf(cache_dir) if cache_dir
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
Cheat.sheets(ARGV) if __FILE__ == $0
|
data/lib/site.rb
ADDED
@@ -0,0 +1,512 @@
|
|
1
|
+
#
|
2
|
+
# According to Wikipedia, Cheat can refer to:
|
3
|
+
# Cheating, to take advantage of a situation by the breaking of accepted rules
|
4
|
+
# or standards
|
5
|
+
# Cheating (casino)
|
6
|
+
# Cheating in poker
|
7
|
+
# Cheating in online games
|
8
|
+
# In relationships, to have an affair
|
9
|
+
# A cheat code, a hidden means of gaining an advantage in a video game
|
10
|
+
# Cheating, parasitic abuse of symbiotic relationships
|
11
|
+
# The Cheat, a character in the cartoon series Homestar Runner
|
12
|
+
# Cheat!, a television show on the G4 network
|
13
|
+
# The Cheat, a 1915 Cecil B. DeMille movie about a wealthy and domineering
|
14
|
+
# Asian gentleman taking advantage of an American female
|
15
|
+
# Cheats, a 2002 comedy, starring Matthew Lawrence and Mary Tyler Moore
|
16
|
+
# Cheat, a song by The Clash from the UK version of their album The Clash
|
17
|
+
# Bullshit, sometimes known as "Cheat," a card game
|
18
|
+
# An alternate term for defection in the prisoner's dilemma in game theory
|
19
|
+
# Cheat River, a tributary of the Monongahela River in Appalachia; the Cheat
|
20
|
+
# starts in West Virginia, and flows westward
|
21
|
+
# Cheat Lake, a nearby resevoir
|
22
|
+
# Cheat Mountain, one of the highest mountains in the Alleghenies
|
23
|
+
#
|
24
|
+
%w[rubygems camping camping/db erb acts_as_versioned wrap].each { |f| require f }
|
25
|
+
require_gem 'camping', '>=1.4.152'
|
26
|
+
|
27
|
+
Camping.goes :Cheat
|
28
|
+
|
29
|
+
URL = 'http://cheat.errtheblog.com' # need this to get around exposing :port in redirects
|
30
|
+
FEED = 'http://feeds.feedburner.com/cheatsheets' # rss feed
|
31
|
+
|
32
|
+
module Cheat::Models
|
33
|
+
class Sheet < Base
|
34
|
+
validates_uniqueness_of :title
|
35
|
+
validates_format_of :title, :with => /^[a-z]+[a-z0-9_]*$/i
|
36
|
+
validates_presence_of :title, :body
|
37
|
+
before_save { |r| r.title = r.title.gsub(' ', '_').underscore.downcase }
|
38
|
+
acts_as_versioned
|
39
|
+
end
|
40
|
+
|
41
|
+
class SetUpUsTheCheat < V 1.0
|
42
|
+
def self.up
|
43
|
+
create_table :cheat_sheets, :force => true do |t|
|
44
|
+
t.column :id, :integer, :null => false
|
45
|
+
t.column :title, :string, :null => false
|
46
|
+
t.column :body, :text
|
47
|
+
t.column :created_at, :datetime, :null => false
|
48
|
+
t.column :updated_at, :datetime, :null => false
|
49
|
+
end
|
50
|
+
Sheet.create_versioned_table
|
51
|
+
Sheet.reset_column_information
|
52
|
+
end
|
53
|
+
def self.down
|
54
|
+
drop_table :cheat_sheets
|
55
|
+
Sheet.drop_versioned_table
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module Cheat::Controllers
|
61
|
+
class APIShow < R '/y/(\w+)'
|
62
|
+
def get(title)
|
63
|
+
@headers['Content-Type'] = 'text/plain'
|
64
|
+
|
65
|
+
sheet = Sheet.find_by_title(title)
|
66
|
+
return { 'Error!' => "Cheat sheet `#{title}' not found." }.to_yaml unless sheet
|
67
|
+
|
68
|
+
return { sheet.title => sheet.body }.to_yaml
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class APIRecent < R '/yr'
|
73
|
+
def get
|
74
|
+
@headers['Content-Type'] = 'text/plain'
|
75
|
+
|
76
|
+
fake = Class.new.send(:include, Cheat::Helpers).new
|
77
|
+
return { 'Recent Cheat Sheets' => fake.recent_sheets.map(&:title) }.to_yaml
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class APIAll < R '/ya'
|
82
|
+
def get
|
83
|
+
@headers['Content-Type'] = 'text/plain'
|
84
|
+
|
85
|
+
return { 'All Cheat Sheets' => Sheet.find(:all, :order => 'title ASC').map(&:title) }.to_yaml
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class Feed < R '/f'
|
90
|
+
def get
|
91
|
+
@headers['Content-Type'] = 'application/xml'
|
92
|
+
return Cheat::Views.feed
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class Index < R '/'
|
97
|
+
def get
|
98
|
+
render :index
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Add < R '/a'
|
103
|
+
def get
|
104
|
+
@sheet = Sheet.new
|
105
|
+
render :add
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class Revert < R '/r/(\w+)/(\d+)'
|
110
|
+
def get(title, version)
|
111
|
+
current = Sheet.find_by_title(title)
|
112
|
+
old = current.find_version(version)
|
113
|
+
current.title, current.body = old.title, old.body
|
114
|
+
current.save
|
115
|
+
redirect "#{URL}/s/#{title}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class Edit < R '/e/(\w+)/(\d+)', '/e/(\w+)'
|
120
|
+
def get(title, version = nil)
|
121
|
+
@sheet = Sheet.find_by_title(title)
|
122
|
+
unless @sheet
|
123
|
+
@error = "Cheat sheet not found."
|
124
|
+
return render(:error)
|
125
|
+
end
|
126
|
+
unless version.nil? || version == @sheet.version.to_s
|
127
|
+
@sheet = @sheet.find_version(version)
|
128
|
+
end
|
129
|
+
render :edit
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class Write < R '/w', '/w/(\w+)'
|
134
|
+
def post(title = nil)
|
135
|
+
@sheet = title ? Sheet.find_by_title(title) : Sheet.new
|
136
|
+
|
137
|
+
@error = input.sheet_body =~ /<a\s*href=/
|
138
|
+
|
139
|
+
if !@error && @sheet.update_attributes(:title => input.sheet_title,
|
140
|
+
:body => input.sheet_body)
|
141
|
+
redirect "#{URL}/s/#{@sheet.title}"
|
142
|
+
else
|
143
|
+
@error = true
|
144
|
+
render title ? :edit : :add
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class Browse < R '/b'
|
150
|
+
def get
|
151
|
+
@sheets = Sheet.find(:all, :order => 'created_at DESC')
|
152
|
+
render :browse
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class Show < R '/s/(\w+)', '/s/(\w+)/(\d+)'
|
157
|
+
def get(title, version = nil)
|
158
|
+
@sheet = Sheet.find_by_title(title)
|
159
|
+
@sheet = @sheet.find_version(version) if version && @sheet
|
160
|
+
if @sheet
|
161
|
+
render :show
|
162
|
+
else
|
163
|
+
redirect "#{URL}/b/"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class History < R '/h/(\w+)'
|
169
|
+
def get(title)
|
170
|
+
@sheets = Sheet.find_by_title(title).find_versions(:order => 'version DESC')
|
171
|
+
render :history
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
module Cheat::Views
|
177
|
+
def layout
|
178
|
+
html {
|
179
|
+
head {
|
180
|
+
_style
|
181
|
+
link :href => FEED, :rel => "alternate", :title => "Recent Cheat Sheets", :type => "application/atom+xml"
|
182
|
+
title defined?(@page_title) ? "$ cheat #{@page_title}" : \
|
183
|
+
"$ command line ruby cheat sheets"
|
184
|
+
}
|
185
|
+
body {
|
186
|
+
#code "Hi this is defunkt. I'm messing around right now (8-9pm pst). Things will get normal soon. thx."
|
187
|
+
div.main {
|
188
|
+
div.header {
|
189
|
+
h1 { logo_link 'cheat sheets.' }
|
190
|
+
code.header defined?(@sheet_title) ? "$ cheat #{@sheet_title}" : \
|
191
|
+
"$ command line ruby cheat sheets"
|
192
|
+
}
|
193
|
+
div.content { self << yield }
|
194
|
+
div.side { _side }
|
195
|
+
div.clear { '' }
|
196
|
+
div.footer { _footer }
|
197
|
+
}
|
198
|
+
}
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
def error
|
203
|
+
@page_title = "error"
|
204
|
+
p "An error:"
|
205
|
+
code.version @error
|
206
|
+
p ":("
|
207
|
+
end
|
208
|
+
|
209
|
+
def show
|
210
|
+
@page_title = @sheet.title
|
211
|
+
@sheet_title = @sheet.title
|
212
|
+
#div.sheet { text h(sheet.body).gsub(/\n(\s+)/, '<br/>' + ' ' * '\1'.size).gsub(/\r/,'').gsub(/\n/,'<br/>') }
|
213
|
+
pre.sheet { text h(sheet.body.wrap(80)) }
|
214
|
+
div.version {
|
215
|
+
text "Version "
|
216
|
+
strong sheet.version
|
217
|
+
text ", updated "
|
218
|
+
text last_updated(@sheet)
|
219
|
+
text " ago. "
|
220
|
+
br
|
221
|
+
text ". o 0 ( "
|
222
|
+
a "edit", :href => R(Edit, @sheet.title)
|
223
|
+
if @sheet.version > 1
|
224
|
+
text " | "
|
225
|
+
a "previous", :href => R(Show, @sheet.title, @sheet.version - 1)
|
226
|
+
text " | "
|
227
|
+
a "history", :href => R(History, @sheet.title)
|
228
|
+
end
|
229
|
+
if @sheet.version != (current = current_sheet).version
|
230
|
+
text " | "
|
231
|
+
a "revert to", :href => R(Revert, @sheet.title, @sheet.version)
|
232
|
+
text " | "
|
233
|
+
a "current", :href => R(Show, @sheet.title, current.version)
|
234
|
+
end
|
235
|
+
text " )"
|
236
|
+
}
|
237
|
+
end
|
238
|
+
|
239
|
+
def browse
|
240
|
+
@page_title = "browse"
|
241
|
+
ul {
|
242
|
+
@sheets.each do |sheet|
|
243
|
+
li { sheet_link sheet.title }
|
244
|
+
end
|
245
|
+
}
|
246
|
+
p {
|
247
|
+
text "Are we missing a cheat sheet? Why don't you do the whole world a favor and "
|
248
|
+
a "add it", :href => R(Add)
|
249
|
+
text " yourself!"
|
250
|
+
}
|
251
|
+
end
|
252
|
+
|
253
|
+
def history
|
254
|
+
@page_title = "history"
|
255
|
+
@sheet_title = @sheets.first.title
|
256
|
+
h2 @sheets.first.title
|
257
|
+
ul {
|
258
|
+
@sheets.each_with_index do |sheet, i|
|
259
|
+
li {
|
260
|
+
a "version #{sheet.version}", :href => R(Show, sheet.title, sheet.version)
|
261
|
+
text " - created "
|
262
|
+
text last_updated(sheet)
|
263
|
+
text " ago"
|
264
|
+
strong " (current)" if i == 0
|
265
|
+
}
|
266
|
+
end
|
267
|
+
}
|
268
|
+
end
|
269
|
+
|
270
|
+
def add
|
271
|
+
@page_title = "add"
|
272
|
+
p {
|
273
|
+
text "Thanks for wanting to add a cheat sheet. If you need an example of
|
274
|
+
the standard cheat sheet format, check out the "
|
275
|
+
a "cheat", :href => R(Show, 'cheat')
|
276
|
+
text " cheat sheet. (There's really no standard format, though)."
|
277
|
+
}
|
278
|
+
_form
|
279
|
+
end
|
280
|
+
|
281
|
+
def edit
|
282
|
+
@page_title = "edit"
|
283
|
+
_form
|
284
|
+
end
|
285
|
+
|
286
|
+
def _form
|
287
|
+
if (@error = @error)
|
288
|
+
p.error {
|
289
|
+
strong "HEY! "
|
290
|
+
text "Something is wrong! You can't give your cheat sheet the same name
|
291
|
+
as another, alphanumeric titles only, and you need to make sure
|
292
|
+
you filled in all (two) of the fields. Okay?"
|
293
|
+
}
|
294
|
+
end
|
295
|
+
form :method => 'post', :action => R(Write, @sheet.title) do
|
296
|
+
p {
|
297
|
+
p {
|
298
|
+
text 'Cheat Sheet Title: '
|
299
|
+
input :value => @sheet.title, :name => 'sheet_title', :size => 30,
|
300
|
+
:type => 'text'
|
301
|
+
small " [ no_spaces_alphanumeric_only ]"
|
302
|
+
}
|
303
|
+
p {
|
304
|
+
text 'Cheat Sheet:'
|
305
|
+
br
|
306
|
+
textarea @sheet.body, :name => 'sheet_body', :cols => 80, :rows => 30
|
307
|
+
}
|
308
|
+
}
|
309
|
+
p "Your cheat sheet will be editable (fixable) by anyone. Each cheat
|
310
|
+
sheet is essentially a wiki page. It may also be used by millions of
|
311
|
+
people for reference purposes from the comfort of their command line.
|
312
|
+
If this is okay with you, please save."
|
313
|
+
input :value => "Save the Damn Thing!", :name => "save", :type => 'submit'
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def index
|
318
|
+
p {
|
319
|
+
text "Welcome. You've reached the central repository for "
|
320
|
+
strong "cheat"
|
321
|
+
text ", the RubyGem which puts Ruby-centric cheat sheets right into your
|
322
|
+
terminal. The inaugural blog entry "
|
323
|
+
a "is here", :href => "http://errtheblog.com/post/23"
|
324
|
+
text "."
|
325
|
+
}
|
326
|
+
p "Get started:"
|
327
|
+
code "$ sudo gem install cheat --source require.errtheblog.com"
|
328
|
+
br
|
329
|
+
code "$ cheat strftime"
|
330
|
+
p "A magnificent cheat sheet for Ruby's strftime method will be printed to
|
331
|
+
your terminal."
|
332
|
+
p "To get some help on cheat itself:"
|
333
|
+
code "$ cheat cheat"
|
334
|
+
p "How meta."
|
335
|
+
p {
|
336
|
+
text "Cheat sheets are basically wiki pages accessible from the command
|
337
|
+
line. You can "
|
338
|
+
a 'browse', :href => R(Browse)
|
339
|
+
text ', '
|
340
|
+
a 'add', :href => R(Add)
|
341
|
+
text ', or '
|
342
|
+
a 'edit', :href => R(Edit, 'cheat')
|
343
|
+
text ' cheat sheets. Try to keep them concise. For a style guide, check
|
344
|
+
out the '
|
345
|
+
a 'cheat', :href => R(Edit, 'cheat')
|
346
|
+
text ' cheat sheet.'
|
347
|
+
}
|
348
|
+
p "To access a cheat sheet, simply pass the program the desired sheet's
|
349
|
+
name:"
|
350
|
+
code "$ cheat <sheet name>"
|
351
|
+
p
|
352
|
+
end
|
353
|
+
|
354
|
+
def self.feed
|
355
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
356
|
+
|
357
|
+
xml.instruct!
|
358
|
+
xml.feed "xmlns"=>"http://www.w3.org/2005/Atom" do
|
359
|
+
|
360
|
+
xml.title "Recent Cheat Sheets"
|
361
|
+
xml.id URL + '/'
|
362
|
+
xml.link "rel" => "self", "href" => FEED
|
363
|
+
|
364
|
+
sheets = Cheat::Models::Sheet.find(:all, :order => 'created_at DESC', :limit => 30)
|
365
|
+
xml.updated sheets.first.created_at.xmlschema
|
366
|
+
|
367
|
+
sheets.each do |sheet|
|
368
|
+
xml.entry do
|
369
|
+
xml.id URL + '/s/' + sheet.title
|
370
|
+
xml.title sheet.title
|
371
|
+
xml.author { xml.name "An Anonymous Cheater" }
|
372
|
+
xml.updated sheet.updated_at.xmlschema
|
373
|
+
xml.link "rel" => "alternate", "href" => URL + '/s/' + sheet.title
|
374
|
+
xml.summary "A cheat sheet about #{sheet.title}. Run it: `$ cheat #{sheet.title}'"
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def _side
|
381
|
+
text '( '
|
382
|
+
a 'add', :href => R(Add)
|
383
|
+
text ' | '
|
384
|
+
a 'browse', :href => R(Browse)
|
385
|
+
text ' )'
|
386
|
+
ul {
|
387
|
+
li { strong "recent cheat sheets" }
|
388
|
+
li do
|
389
|
+
a :href => FEED do
|
390
|
+
img(:alt => "Recent Cheat Sheets Feed", :src => "http://errtheblog.com/images/theme/feed.png")
|
391
|
+
end
|
392
|
+
end
|
393
|
+
recent_sheets.each do |sheet|
|
394
|
+
li { sheet_link sheet.title }
|
395
|
+
end
|
396
|
+
}
|
397
|
+
end
|
398
|
+
|
399
|
+
def _footer
|
400
|
+
text "Powered by "
|
401
|
+
a 'Camping', :href => "http://code.whytheluckystiff.net/camping"
|
402
|
+
text ", "
|
403
|
+
a 'Mongrel', :href => "http://mongrel.rubyforge.org/"
|
404
|
+
text " and, to a lesser extent, "
|
405
|
+
a 'Err the Blog', :href => "http://errtheblog.com/"
|
406
|
+
text "."
|
407
|
+
end
|
408
|
+
|
409
|
+
def _style
|
410
|
+
bg = "#fff"
|
411
|
+
h1 = "#4fa3da"
|
412
|
+
link = h1
|
413
|
+
hover = "#f65077"
|
414
|
+
dash = hover
|
415
|
+
version = "#fcf095"
|
416
|
+
style :type => "text/css" do
|
417
|
+
text %{
|
418
|
+
body { font-family: verdana, sans-serif; background-color: #{bg};
|
419
|
+
line-height: 20px; }
|
420
|
+
a:link, a:visited { color: #{link}; }
|
421
|
+
a:hover { text-decoration: none; color: #{hover}; }
|
422
|
+
div.header { border-bottom: 1px dashed #{dash}; }
|
423
|
+
code.header { margin-left: 30px; font-weight: bold;
|
424
|
+
background-color: #{version}; }
|
425
|
+
h1 { font-size: 5em; margin: 0; padding-left: 30px; color: #{h1};
|
426
|
+
clear: both; font-weight: bold; letter-spacing: -5px; }
|
427
|
+
div.main { float: left; width: 100%; }
|
428
|
+
div.content { float: left; width: 70%; padding: 15px 0 15px 30px;
|
429
|
+
line-height: 20px; }
|
430
|
+
div.side { float: left; padding: 10px; text-align: right;
|
431
|
+
width: 20%; }
|
432
|
+
div.footer { text-align: center; border-top: 1px dashed #{dash};
|
433
|
+
padding-top: 10px; font-size: small; }
|
434
|
+
div.sheet { font-size: .8em; line-height: 17px; padding: 5px;
|
435
|
+
font-family: courier, fixed-width; background-color: #e8e8e8; }
|
436
|
+
pre.sheet { line-height: 15px; }
|
437
|
+
li { list-style: none; }
|
438
|
+
div.version { background-color: #{version}; padding: 5px;
|
439
|
+
width: 450px; margin-top: 50px; }
|
440
|
+
p.error { background-color: #{version}; padding: 5px; }
|
441
|
+
div.clear { clear: both; }
|
442
|
+
div.clear_10 { clear: both; font-size: 10px; line-height: 10px; }
|
443
|
+
textarea { font-family: courier; }
|
444
|
+
code { background-color: #{version} }
|
445
|
+
}.gsub(/(\s{2,})/, '').gsub("\n", '')
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
module Cheat::Helpers
|
451
|
+
def logo_link(title)
|
452
|
+
ctr = Cheat::Controllers
|
453
|
+
if @sheet && !@sheet.new_record? && @sheet.version != current_sheet.version
|
454
|
+
a title, :href => R(ctr::Show, @sheet.title, current_sheet.version)
|
455
|
+
else
|
456
|
+
a title, :href => R(ctr::Index)
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
def current_sheet
|
461
|
+
@current_sheet ||= Cheat::Models::Sheet.find_by_title(@sheet.title)
|
462
|
+
end
|
463
|
+
|
464
|
+
def recent_sheets
|
465
|
+
Cheat::Models::Sheet.find(:all, :order => 'created_at DESC', :limit => 10)
|
466
|
+
end
|
467
|
+
|
468
|
+
def sheet_link(title, version = nil)
|
469
|
+
a title, :href => R(Cheat::Controllers::Show, title, version)
|
470
|
+
end
|
471
|
+
|
472
|
+
def last_updated(sheet)
|
473
|
+
from = sheet.updated_at.to_i
|
474
|
+
to = Time.now.to_i
|
475
|
+
from = from.to_time if from.respond_to?(:to_time)
|
476
|
+
to = to.to_time if to.respond_to?(:to_time)
|
477
|
+
distance = (((to - from).abs)/60).round
|
478
|
+
case distance
|
479
|
+
when 0..1 : return (distance==0) ? 'less than a minute' : '1 minute'
|
480
|
+
when 2..45 : "#{distance} minutes"
|
481
|
+
when 46..90 : 'about 1 hour'
|
482
|
+
when 90..1440 : "about #{(distance.to_f / 60.0).round} hours"
|
483
|
+
when 1441..2880: '1 day'
|
484
|
+
else "#{(distance / 1440).round} days"
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
def h(text)
|
489
|
+
ERB::Util::h(text)
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
def Cheat.create
|
494
|
+
Cheat::Models.create_schema
|
495
|
+
end
|
496
|
+
|
497
|
+
if __FILE__ == $0
|
498
|
+
begin
|
499
|
+
require 'mongrel/camping'
|
500
|
+
rescue LoadError => e
|
501
|
+
abort "** Try running `camping #$0' instead."
|
502
|
+
end
|
503
|
+
|
504
|
+
Cheat::Models::Base.establish_connection :adapter => 'mysql', :user => 'root', :database => 'camping', :host => 'localhost'
|
505
|
+
Cheat::Models::Base.logger = nil
|
506
|
+
Cheat::Models::Base.threaded_connections = false
|
507
|
+
Cheat.create
|
508
|
+
|
509
|
+
server = Mongrel::Camping.start("0.0.0.0", 3001, "/", Cheat)
|
510
|
+
puts "** Cheat is running at http://0.0.0.0:3001/"
|
511
|
+
server.run.join
|
512
|
+
end
|
data/lib/wrap.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# >> Evan Weaver
|
2
|
+
# => http://blog.evanweaver.com/articles/2006/09/03/smart-plaintext-wrapping
|
3
|
+
class String
|
4
|
+
def wrap(width, hanging_indent = 0, magic_lists = false)
|
5
|
+
lines = self.split(/\n/)
|
6
|
+
|
7
|
+
lines.collect! do |line|
|
8
|
+
|
9
|
+
if magic_lists
|
10
|
+
line =~ /^([\s\-\d\.\:]*\s)/
|
11
|
+
else
|
12
|
+
line =~ /^([\s]*\s)/
|
13
|
+
end
|
14
|
+
|
15
|
+
indent = $1.length + hanging_indent rescue hanging_indent
|
16
|
+
|
17
|
+
buffer = ""
|
18
|
+
first = true
|
19
|
+
|
20
|
+
while line.length > 0
|
21
|
+
first ? (i, first = 0, false) : i = indent
|
22
|
+
pos = width - i
|
23
|
+
|
24
|
+
if line.length > pos and line[0..pos] =~ /^(.+)\s/
|
25
|
+
subline = $1
|
26
|
+
else
|
27
|
+
subline = line[0..pos]
|
28
|
+
end
|
29
|
+
buffer += " " * i + subline + "\n"
|
30
|
+
line.tail!(subline.length)
|
31
|
+
end
|
32
|
+
buffer[0..-2]
|
33
|
+
end
|
34
|
+
|
35
|
+
lines.join("\n")
|
36
|
+
end
|
37
|
+
|
38
|
+
def tail!(pos)
|
39
|
+
self[0..pos] = ""
|
40
|
+
strip!
|
41
|
+
end
|
42
|
+
end
|
data/test/test_cheat.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# eh. one day.
|
2
|
+
$:.unshift File.dirname(__FILE__) + "/..:lib"
|
3
|
+
require 'test/unit'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'tempfile'
|
6
|
+
require 'cheat'
|
7
|
+
|
8
|
+
Sheets = Hash.new do |h,k|
|
9
|
+
k = k.to_s
|
10
|
+
h[k] = YAML.load(File.read("test/fixtures/#{k}.yml")) rescue nil
|
11
|
+
end
|
12
|
+
|
13
|
+
class CheatTest < Test::Unit::TestCase
|
14
|
+
|
15
|
+
def test_gets_from_host
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_sets_to_cache
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_gets_from_arbitrary_host
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_gracefully_fail_if_host_bunk
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_creates_cache_dir
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_doesnt_create_cache_dir_if_exists
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_loads_from_cache_if_exists
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_gets_section_if_exists
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_displays_everything_on_failed_section_search
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_gets_recent_sheets
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_gets_all_sheets
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_uses_env_for_cache_dir
|
49
|
+
end
|
50
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: cheat
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.2
|
7
|
+
date: 2006-09-03 00:00:00 -07:00
|
8
|
+
summary: Cheat is a simple command line utility reference program.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: chris@ozmm.org
|
12
|
+
homepage: http://cheat.errtheblog.com/
|
13
|
+
rubyforge_project:
|
14
|
+
description: Cheat is a simple command line utility reference program. Use it to, well, cheat.
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Chris Wanstrath
|
31
|
+
files:
|
32
|
+
- README
|
33
|
+
- LICENSE
|
34
|
+
- bin/cheat
|
35
|
+
- lib/cheat.rb
|
36
|
+
- lib/site.rb
|
37
|
+
- lib/wrap.rb
|
38
|
+
- test/fixtures
|
39
|
+
- test/test_cheat.rb
|
40
|
+
test_files: []
|
41
|
+
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
extra_rdoc_files: []
|
45
|
+
|
46
|
+
executables:
|
47
|
+
- cheat
|
48
|
+
extensions: []
|
49
|
+
|
50
|
+
requirements: []
|
51
|
+
|
52
|
+
dependencies: []
|
53
|
+
|