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.
Files changed (4) hide show
  1. checksums.yaml +15 -0
  2. data/bin/bro +3 -0
  3. data/lib/bro.rb +323 -0
  4. 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
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bro'
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: []