bropages 0.0.3
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.
- checksums.yaml +15 -0
- data/bin/bro +3 -0
- data/lib/bro.rb +323 -0
- metadata +116 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NGUzZTk4OGZlNGJkNmI3NWQxM2IxMzdlNjA0YjI2MWViOTcyM2FjNA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MmYwZjg2OTMzN2VjYmI2ZTQzYWUxMDY2NDRhMzA4NzkzNTJhZTIzZg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NDAyNTJmMDFmMGQ1MzNkMGJhZTBmNzM1NDUzYTAyNDIzOGUyYzYxODg1Y2Jj
|
10
|
+
MmY3MDBhZWIyYjVhMDEwZjYwNjc5YTUzMDgwYWFmZTZkNzY0MzNmNDU0Mzhi
|
11
|
+
MTFkZWEzY2Q5ZjQwNDk2ZDhmNzdjYzliOTFjNWNhNmZmYzQ3MzI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NThhNDc3N2M4NzRkNzY1ZDdiZmE2ZWU4OGQ4MWQ2MzVmMTIyOGZiZmE0ZmFl
|
14
|
+
NDA1YWUzMWM1ZDAyZTQ1NDVlMTBhZGRhZGJmMzkyZDUxNTdjYWVkNGVjOTI5
|
15
|
+
YjRlNzM5OTFhNDA4MzI2ODc4NDA1ZWYwNWQwOGExZmYzMTA5Nzk=
|
data/bin/bro
ADDED
data/lib/bro.rb
ADDED
@@ -0,0 +1,323 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'json'
|
4
|
+
require 'commander/import'
|
5
|
+
require 'highline'
|
6
|
+
require 'smart_colored'
|
7
|
+
require 'rest-client'
|
8
|
+
|
9
|
+
URL = ENV["BROPAGES_URL"] || 'http://bropages.org'
|
10
|
+
FILE = ENV["HOME"] + '/.bro'
|
11
|
+
|
12
|
+
program :name, 'bro'
|
13
|
+
program :version, '0.0.3'
|
14
|
+
program :description, "Highly readable supplement to man pages.\n\nShows simple, concise examples for commands."
|
15
|
+
|
16
|
+
default_command :lookup
|
17
|
+
|
18
|
+
command :thanks do |c|
|
19
|
+
c.syntax = 'bro thanks [COMMAND]'
|
20
|
+
c.summary = 'Upvote an entry, bro'
|
21
|
+
c.description = 'Upvote a bro entry. If called without a COMMAND argument, it will upvote the last thing you looked up with bro'
|
22
|
+
c.example 'Upvote the bro entry for curl', 'bro thanks curl'
|
23
|
+
c.action do |args, options|
|
24
|
+
begin
|
25
|
+
login_details = check_email
|
26
|
+
rescue
|
27
|
+
say "Sorry, you can't do this without email verification".colored.red
|
28
|
+
end
|
29
|
+
unless login_details.nil?
|
30
|
+
cmd = read_state[:cmd]
|
31
|
+
|
32
|
+
if cmd.nil?
|
33
|
+
say "\nYou must first look up a command before downvoting. For example: bro curl\n\n"
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
idkey = args[0]
|
38
|
+
if idkey.nil?
|
39
|
+
idkey = "1"
|
40
|
+
end
|
41
|
+
id = read_state[idkey.intern]
|
42
|
+
|
43
|
+
if id.nil?
|
44
|
+
say "\nThat id (#{idkey}) does not exist for #{cmd}, try another one"
|
45
|
+
return
|
46
|
+
end
|
47
|
+
|
48
|
+
begin
|
49
|
+
res = RestClient.get URL + "/thanks/#{id}", { params: login_details }
|
50
|
+
rescue => e
|
51
|
+
say e.message
|
52
|
+
say "There was a problem thanking the #{cmd} entry. This entry may not exist or bropages.org may be down".colored.yellow.on_red
|
53
|
+
else
|
54
|
+
say "You just gave thanks for the top entry for #{cmd}!"
|
55
|
+
say res
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
command :no do |c|
|
62
|
+
c.syntax = 'bro no [ID]'
|
63
|
+
c.summary = 'Downvote an entry, bro'
|
64
|
+
c.description = 'Downvote a bro entry for the last command you looked up. If called without ID, it will downvote the top entry of the last command you looked up.'
|
65
|
+
c.example 'Downvote the bro entry for curl', "bro curl\n\nbro no"
|
66
|
+
c.action do |args, options|
|
67
|
+
begin
|
68
|
+
login_details = check_email
|
69
|
+
rescue
|
70
|
+
say "Sorry, you can't do this without email verification".colored.red
|
71
|
+
end
|
72
|
+
unless login_details.nil?
|
73
|
+
|
74
|
+
cmd = read_state[:cmd]
|
75
|
+
|
76
|
+
if cmd.nil?
|
77
|
+
say "\nYou must first look up a command before downvoting. For example: bro curl\n\n"
|
78
|
+
return
|
79
|
+
end
|
80
|
+
|
81
|
+
idkey = args[0]
|
82
|
+
if idkey.nil?
|
83
|
+
idkey = "1"
|
84
|
+
end
|
85
|
+
id = read_state[idkey.intern]
|
86
|
+
|
87
|
+
if id.nil?
|
88
|
+
say "\nThat id (#{idkey}) does not exist for #{cmd}, try another one"
|
89
|
+
return
|
90
|
+
end
|
91
|
+
|
92
|
+
begin
|
93
|
+
res = RestClient.get URL + "/no/#{id}", { params: login_details }
|
94
|
+
rescue => e
|
95
|
+
say e.message
|
96
|
+
say "There was a problem downvoting the #{cmd} entry. This entry may not exist or bropages.org may be down".colored.yellow.on_red
|
97
|
+
else
|
98
|
+
say "You just downvoted an entry for #{cmd}"
|
99
|
+
say res
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
command :add do |c|
|
106
|
+
c.syntax = 'bro add [COMMAND] [-m MESSAGE]'
|
107
|
+
c.summary = 'Add an entry, bro'
|
108
|
+
c.description = "This adds an entry to the http://bropages.org database.\n\nCalled without parameters will add an entry for the last thing you looked up with bro."
|
109
|
+
c.example 'Launch your editor to add an entry for curl', 'bro add curl'
|
110
|
+
c.example 'Quickly add an entry for curl', 'bro add curl -m "curl http://google.com"'
|
111
|
+
#TODO c.option '-m', 'An optional inline entry. This won\'t trigger a system editor to open'
|
112
|
+
c.action do |args, options|
|
113
|
+
begin
|
114
|
+
login_details = check_email
|
115
|
+
rescue
|
116
|
+
say "Sorry, you can't do this without email verification".colored.red
|
117
|
+
end
|
118
|
+
|
119
|
+
unless login_details.nil?
|
120
|
+
|
121
|
+
cmd = get_arg_or_last_command args
|
122
|
+
|
123
|
+
if cmd.nil?
|
124
|
+
say "\nYou must enter a COMMAND after 'bro add'. For example: bro add curl\n\n"
|
125
|
+
else
|
126
|
+
prompt = "#~ Bro entry for command '#{cmd}'\n#~ Just provide a few, simple, common case examples for how to use this command\n#~ Comments starting with #~ are removed\n"
|
127
|
+
entry = ask_editor prompt, "vim"
|
128
|
+
if entry.gsub(prompt, '').strip.length > 0
|
129
|
+
if agree "Submit this entry for #{cmd}? [Yn] "
|
130
|
+
say "All right, sending your entry..."
|
131
|
+
begin
|
132
|
+
res = RestClient.post URL + '/', login_details.merge({ entry: { cmd: cmd, msg: entry}, format: 'json', multipart: true })
|
133
|
+
rescue => e
|
134
|
+
say e.message
|
135
|
+
file = "/tmp/#{cmd}.bro"
|
136
|
+
|
137
|
+
# increment file name as to not overwrite anything
|
138
|
+
i = 1
|
139
|
+
while File.exist?(file)
|
140
|
+
file = "/tmp/#{cmd}#{i}.bro"
|
141
|
+
i += 1
|
142
|
+
end
|
143
|
+
|
144
|
+
# write message to file
|
145
|
+
File.open(file, 'w') do |f|
|
146
|
+
f.write entry
|
147
|
+
end
|
148
|
+
say "Woops. There was an error! Your entry was saved to #{file}".colored.yellow.on_red
|
149
|
+
else
|
150
|
+
say "Successfully submitted.".colored.green
|
151
|
+
end
|
152
|
+
end
|
153
|
+
else
|
154
|
+
say "Canceled. Did not submit entry for '#{cmd}'".colored.yellow.on_red
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
command :lookup do |c|
|
162
|
+
c.syntax = 'bro [COMMAND]'
|
163
|
+
c.summary = 'Lookup an entry, bro. Or just call bro [COMMAND]'
|
164
|
+
c.description = "This looks up entries in the http://bropages.org database."
|
165
|
+
c.example 'Look up the bro entries for curl', 'bro curl'
|
166
|
+
c.action do |args, options|
|
167
|
+
if args.empty?
|
168
|
+
say "\n#{"Bro! Specify a command first!".colored.red}\n\nFor example, try #{"bro curl".colored.green}\n\nUse #{"bro help".colored.yellow} for more info\n\n"
|
169
|
+
else
|
170
|
+
cmd = args.first
|
171
|
+
|
172
|
+
# write to ~/.bro file with last command
|
173
|
+
write_state({ cmd: cmd })
|
174
|
+
|
175
|
+
# connect to webservice for entry
|
176
|
+
error = false
|
177
|
+
begin
|
178
|
+
res = RestClient.get URL + '/' + cmd + '.json'
|
179
|
+
rescue => e
|
180
|
+
say "\nThe #{cmd.colored.yellow} command isn't in our database\n\n\t* Use #{"bro add".colored.green.underline} to add #{cmd.colored.yellow} to our database!\n\n\t* Need help? Visit #{"http://bropages.org/help".colored.underline}\n\n"
|
181
|
+
error = true
|
182
|
+
end
|
183
|
+
|
184
|
+
unless error
|
185
|
+
enable_paging
|
186
|
+
list = JSON.parse res
|
187
|
+
s = list.length == 1 ? 'y' : 'ies'
|
188
|
+
say "#{list.length} entr#{s} for #{cmd}\n".colored.yellow.bold.underline
|
189
|
+
|
190
|
+
sep = ""
|
191
|
+
(HighLine::SystemExtensions.terminal_size[0] - 5).times { sep += "." }
|
192
|
+
sep += "\n"
|
193
|
+
|
194
|
+
i = 0
|
195
|
+
isDefault = true
|
196
|
+
list.each {|data|
|
197
|
+
i += 1
|
198
|
+
|
199
|
+
obj = {}
|
200
|
+
obj["#{i}"] = data['id']
|
201
|
+
write_state(obj)
|
202
|
+
|
203
|
+
days = (DateTime.now - DateTime.parse(data['updated_at'])).ceil.to_i
|
204
|
+
|
205
|
+
body = data['msg']
|
206
|
+
|
207
|
+
body = body.gsub(/^([^#][^\n]*)$/, "\\1".colored.magenta)
|
208
|
+
|
209
|
+
say sep + "\n\n" if i > 1
|
210
|
+
|
211
|
+
say body + "\n\n"
|
212
|
+
|
213
|
+
upstr = "bro thanks"
|
214
|
+
upstr += " #{i}" unless isDefault
|
215
|
+
downstr = "bro no"
|
216
|
+
downstr += " #{i}" unless isDefault
|
217
|
+
downstr += "\t" if isDefault
|
218
|
+
|
219
|
+
msg = "\t#{upstr.colored.green}\tto upvote (#{data['up']})\n\t#{downstr.colored.red}\tto downvote (#{data['down']})\n"
|
220
|
+
if days > 0
|
221
|
+
#msg += "\tlast updated\t#{days} days ago"
|
222
|
+
end
|
223
|
+
say msg + "\n\n"
|
224
|
+
isDefault = false
|
225
|
+
}
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def get_arg_or_last_command args
|
232
|
+
cmd = args.first
|
233
|
+
if args.empty?
|
234
|
+
state = read_state
|
235
|
+
cmd = state[:cmd]
|
236
|
+
end
|
237
|
+
cmd
|
238
|
+
end
|
239
|
+
|
240
|
+
def check_email
|
241
|
+
begin
|
242
|
+
is_invalid_code read_state[:code], read_state[:email]
|
243
|
+
rescue => e
|
244
|
+
prompt_email
|
245
|
+
end
|
246
|
+
{code: read_state[:code], email: read_state[:email]}
|
247
|
+
end
|
248
|
+
|
249
|
+
def prompt_email
|
250
|
+
say "Bropages.org requires an email address verification to do this action".colored.yellow
|
251
|
+
say "Your email address and verification code will be saved locally on your machine to a file called #{"~/.bro".colored.yellow} and used for future bropages.org activity"
|
252
|
+
say "When you enter your email, you'll get a verification email with a code. Enter the code when prompted"
|
253
|
+
|
254
|
+
email = ""
|
255
|
+
|
256
|
+
while is_invalid_email email
|
257
|
+
email = ask "What's your email address?".colored.green
|
258
|
+
end
|
259
|
+
|
260
|
+
begin
|
261
|
+
res = RestClient.post URL + '/users.json', { user: { email: email }, format: 'json', multipart: true }
|
262
|
+
rescue => e
|
263
|
+
say "There was an error delivering to your email address. Please try again later".colored.yellow.on_red
|
264
|
+
raise e
|
265
|
+
else
|
266
|
+
say "Great! We're sending an email to #{email}. Enter the verification code below and you'll be all set from now on."
|
267
|
+
|
268
|
+
invalid_code = true
|
269
|
+
begin
|
270
|
+
code = ask "Please enter the verification code: "
|
271
|
+
begin
|
272
|
+
is_invalid_code code, email
|
273
|
+
invalid_code = false
|
274
|
+
say "Great! You're verified! FYI, your email and code are stored locally in ~/.bro"
|
275
|
+
write_state({ email: email, code: code })
|
276
|
+
rescue => e
|
277
|
+
say "Woops, there was a problem verifying your email. Please try again".colored.yellow.on_red
|
278
|
+
end
|
279
|
+
end while invalid_code
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
def is_invalid_code code, email
|
285
|
+
res = RestClient.get URL + "/users/verify?code=#{code}&email=#{email}"
|
286
|
+
end
|
287
|
+
|
288
|
+
def is_invalid_email email
|
289
|
+
regex = /^[a-zA-Z0-9_.+\-]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-.]+$/
|
290
|
+
email.scan(regex).empty?
|
291
|
+
end
|
292
|
+
|
293
|
+
# write state to this file, using the existing key/vals as defaults
|
294
|
+
# format is key=val;key2=val;key3=val
|
295
|
+
def write_state obj
|
296
|
+
# read the ~/.bro file and load the settings as defaults
|
297
|
+
# we don't want to lose data if we're not writing over it all
|
298
|
+
read_state.each {|k,v|
|
299
|
+
obj[k] = v if obj[k].nil?
|
300
|
+
}
|
301
|
+
|
302
|
+
# actually serialize the data and write the file
|
303
|
+
File.open(FILE, 'w') do |file|
|
304
|
+
data_pairs = obj.collect{ |k,v| "#{k}=#{v}" }
|
305
|
+
file.write data_pairs.join(";") + "\n"
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
# read the ~/.bro file and return a hash of the values
|
310
|
+
def read_state
|
311
|
+
obj = {}
|
312
|
+
begin
|
313
|
+
contents = File.read FILE
|
314
|
+
contents.strip.split(";").each {|kv|
|
315
|
+
chunk = kv.split("=")
|
316
|
+
key = chunk[0].intern
|
317
|
+
obj[key] = chunk[1]
|
318
|
+
}
|
319
|
+
rescue => e
|
320
|
+
# ignore file not found
|
321
|
+
end
|
322
|
+
obj
|
323
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bropages
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- bropages.org
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: commander
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rest-client
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: smart_colored
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: highline
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Highly readable supplement to man pages. Shows simple, concise examples
|
84
|
+
for unix commands.
|
85
|
+
email: info@bropages.org
|
86
|
+
executables:
|
87
|
+
- bro
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- bin/bro
|
92
|
+
- lib/bro.rb
|
93
|
+
homepage: http://bropages.org
|
94
|
+
licenses: []
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.2.1
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: Bro
|
116
|
+
test_files: []
|