wb-bropages 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8e411d0f0c328a1b8e76a7c2f69ca039ca146101
4
+ data.tar.gz: 1b0701504b63f542511399e04cdff4ad91449abf
5
+ SHA512:
6
+ metadata.gz: a9588213a91a25dddcb7685d656d3a16b53878d967f252751405eb0bd9dcbbe1f1793a8ef7e73ccb5adf74306524cf32f8d3cfd6b231a8201e4451a57993ac71
7
+ data.tar.gz: 0f7e43045244834f47ec81a785c3ffd27c5d4962f128dd9c60bb1c84c224990070a79c96efb8997862b30e29a9d165455bdc08edc4e7386a4050a55ee8a53c37
data/bin/bro ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bro'
@@ -0,0 +1,84 @@
1
+ module Bro
2
+ class BroState < State
3
+ COLOR_OFF = "nocolor"
4
+
5
+ # true/false if color should be used
6
+ def check_color
7
+ state = read_state
8
+ return state[:color] != COLOR_OFF
9
+ end
10
+
11
+ def get_arg_or_last_command args
12
+ cmd = args.join(" ")
13
+ if args.empty?
14
+ state = read_state
15
+ cmd = state[:cmd]
16
+ return nil if state.nil? or cmd.nil?
17
+ cmd.strip!
18
+ end
19
+ cmd
20
+ end
21
+
22
+ def reset_lookup_ids
23
+ # drop all lookup ids
24
+ new_state = read_state().delete_if { |k, v| !!(k =~ /\d+/) }
25
+ write_state(new_state, true)
26
+ end
27
+
28
+ def check_email
29
+ begin
30
+ is_invalid_code read_state[:code], read_state[:email]
31
+ rescue => e
32
+ prompt_email
33
+ end
34
+ { :code => read_state[:code], :email => read_state[:email]}
35
+ end
36
+
37
+ def prompt_email
38
+ say "Bropages.org requires an email address verification to do this".colored.yellow
39
+
40
+ email = ""
41
+
42
+ begin
43
+ while is_invalid_email email
44
+ email = ask "What's your email address?".colored.green
45
+ end
46
+ begin
47
+ email_param = CGI.escape(email)
48
+ res = RestClient.post URL + '/users.json', { :user => { :email => email_param }, :format => 'json', :multipart => true }
49
+ rescue => e
50
+ say "There was an error delivering to your email address. Please try again later".colored.yellow.on_red
51
+ raise e
52
+ else
53
+ say "Great! We're sending an email to #{email}".success
54
+
55
+ invalid_code = true
56
+ begin
57
+ code = ask "Please enter the verification code: "
58
+ begin
59
+ is_invalid_code code, email
60
+ invalid_code = false
61
+ say "Great! You're verified! FYI, your email and code are stored locally in ~/.bro".success
62
+ write_state({ :email => email, :code => code })
63
+ rescue => e
64
+ say "Woops, there was a problem verifying your email. Please try again".colored.yellow.on_red
65
+ end
66
+ end while invalid_code
67
+ end
68
+ rescue Interrupt
69
+ say "Canceled email verification".status
70
+ raise
71
+ end
72
+ end
73
+
74
+ def is_invalid_code code, email
75
+ email_param = CGI.escape(email)
76
+ res = RestClient.get URL + "/users/verify?code=#{code}&email=#{email_param}"
77
+ end
78
+
79
+ def is_invalid_email email
80
+ regex = /^[a-zA-Z0-9_.+\-]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-.]+$/
81
+ email.scan(regex).empty?
82
+ end
83
+ end
84
+ end
data/lib/bro/state.rb ADDED
@@ -0,0 +1,40 @@
1
+ module Bro
2
+ class State
3
+
4
+ def initialize options
5
+ @file = options[:file]
6
+ end
7
+
8
+ # write state to this file, using the existing key/vals as defaults
9
+ # format is key=val;key2=val;key3=val
10
+ def write_state obj, override=false
11
+ # read the ~/.bro file and load the settings as defaults
12
+ # we don't want to lose data if we're not writing over it all
13
+ read_state.each {|k,v|
14
+ obj[k] = v if obj[k].nil?
15
+ } unless override # unless we pass in strict parsing
16
+
17
+ # actually serialize the data and write the file
18
+ File.open(@file, 'w') do |file|
19
+ data_pairs = obj.collect{ |k,v| "#{k}=#{v}" }
20
+ file.write data_pairs.join(";") + "\n"
21
+ end
22
+ end
23
+
24
+ # read the ~/.bro file and return a hash of the values
25
+ def read_state
26
+ obj = {}
27
+ begin
28
+ contents = File.read @file
29
+ contents.strip.split(";").each {|kv|
30
+ chunk = kv.split("=")
31
+ key = chunk[0].intern
32
+ obj[key] = chunk[1]
33
+ }
34
+ rescue => e
35
+ # ignore file not found
36
+ end
37
+ obj
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,63 @@
1
+ class FakeColor
2
+ def initialize(text); @text = text; end
3
+
4
+ %w{ red green yellow blue underline }.each do |m|
5
+ define_method(m){ @text }
6
+ end
7
+ end
8
+
9
+ class VanillaText
10
+ class << self
11
+ def apply
12
+ String.class_eval do
13
+ def colored
14
+ FakeColor.new self
15
+ end
16
+
17
+ def unindent
18
+ gsub(/^#{scan(/^\s*/).min_by{|l|l.length}}/, "")
19
+ end
20
+ end
21
+
22
+ %w{ status success problem sorry important underline }.each do |m|
23
+ String.class_eval do
24
+ define_method(m){ self }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ class ColoredText
32
+ class << self
33
+ def apply
34
+ String.class_eval do
35
+ require 'smart_colored'
36
+
37
+ def unindent
38
+ gsub(/^#{scan(/^\s*/).min_by{|l|l.length}}/, "")
39
+ end
40
+
41
+ def status
42
+ self.colored.yellow
43
+ end
44
+
45
+ def success
46
+ self.colored.green.bold
47
+ end
48
+
49
+ def problem
50
+ self.colored.yellow_on_red_bold
51
+ end
52
+
53
+ def sorry
54
+ self.colored.red.bold
55
+ end
56
+
57
+ def important
58
+ self.colored.magenta
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module Bro
2
+ VERSION = "1.0.0"
3
+ end
data/lib/bro.rb ADDED
@@ -0,0 +1,350 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # 1.8.7 support
4
+ unless Kernel.respond_to?(:require_relative)
5
+ module Kernel
6
+ def require_relative(path)
7
+ require File.join(File.dirname(caller[0]), path.to_str)
8
+ end
9
+ end
10
+ end
11
+
12
+ require 'rubygems'
13
+ require 'json'
14
+ require 'commander/import'
15
+ require 'highline'
16
+ require 'rest-client'
17
+
18
+ require_relative 'bro/state.rb'
19
+ require_relative 'bro/bro_state.rb'
20
+ require_relative 'bro/string_hacks.rb'
21
+ require_relative 'bro/version.rb'
22
+
23
+ URL = ENV["BROPAGES_URL"] || 'http://bropages.org'
24
+ FILE = ENV["HOME"] + '/.bro'
25
+ RestClient.proxy = ENV['http_proxy']
26
+
27
+ program :name, 'bro'
28
+ program :version, Bro::VERSION
29
+ program :description, "Highly readable supplement to man pages.\n\nShows simple, concise examples for commands."
30
+ default_command :lookup
31
+
32
+ state = Bro::BroState.new({:file => FILE})
33
+
34
+ if state.check_color
35
+ ColoredText.apply
36
+ else
37
+ VanillaText.apply
38
+ end
39
+
40
+ yesblock = lambda { |c|
41
+ c.syntax = 'bro thanks [COMMAND]'
42
+ c.summary = 'Upvote an entry, bro'
43
+ c.description = 'Upvote a bro entry. If called without a COMMAND argument, it will upvote the last thing you looked up with bro'
44
+ c.example 'Upvote the bro entry for curl', 'bro thanks curl'
45
+ c.action do |args, options|
46
+ begin
47
+ login_details = state.check_email
48
+ rescue Interrupt, StandardError
49
+ say "Sorry, you can't do this without email verification".sorry
50
+ end
51
+ unless login_details.nil?
52
+ cmd = state.read_state[:cmd]
53
+
54
+ if cmd.nil?
55
+ say "\nYou must first look up a command before downvoting. For example: bro curl\n\n".sorry
56
+ return
57
+ end
58
+
59
+ idkey = args[0]
60
+ if idkey.nil?
61
+ idkey = "1"
62
+ end
63
+ id = state.read_state[idkey.intern]
64
+
65
+ if id.nil?
66
+ say "That index (#{idkey}) does not exist for #{cmd}, try another one".sorry
67
+ end
68
+
69
+ unless id.nil?
70
+ begin
71
+ RestClient.get URL + "/thanks/#{id}", { :params => login_details }
72
+ rescue => e
73
+ say e.message
74
+ say "There was a problem thanking the #{cmd} entry. This entry may not exist or bropages.org may be down".problem
75
+ else
76
+ say "You just gave thanks to an entry for #{cmd}!".status
77
+ say "You rock!".success
78
+ end
79
+ end
80
+ end
81
+ end
82
+ }
83
+
84
+ command :thanks, &yesblock
85
+ command :ty, &yesblock
86
+
87
+ noblock = lambda { |c|
88
+ c.syntax = 'bro ...no [ID]'
89
+ c.summary = 'Downvote an entry, bro'
90
+ 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.'
91
+ c.example 'Downvote the bro entry for curl', "bro curl\n\nbro ...no"
92
+ c.action do |args, options|
93
+ begin
94
+ login_details = state.check_email
95
+ rescue Interrupt, StandardError
96
+ say "Sorry, you can't do this without email verification".sorry
97
+ end
98
+ unless login_details.nil?
99
+
100
+ cmd = state.read_state[:cmd]
101
+
102
+ if cmd.nil?
103
+ say "\nYou must first look up a command before downvoting. For example: bro curl\n\n".sorry
104
+ return
105
+ end
106
+
107
+ idkey = args[0]
108
+ if idkey.nil?
109
+ idkey = "1"
110
+ end
111
+ id = state.read_state[idkey.intern]
112
+
113
+ if id.nil?
114
+ say "That id (#{idkey}) does not exist for #{cmd}, try another one".sorry
115
+ end
116
+
117
+ unless id.nil?
118
+ begin
119
+ RestClient.get URL + "/no/#{id}", { :params => login_details }
120
+ rescue => e
121
+ say "There was a problem downvoting the #{cmd} entry. This entry may not exist or bropages.org may be down".problem
122
+ say e
123
+ else
124
+ say "You just downvoted an entry for #{cmd}".status
125
+ say "You rock!".success
126
+ end
127
+ end
128
+ end
129
+ end
130
+ }
131
+
132
+ command :"...no", &noblock
133
+ command :no, &noblock
134
+
135
+ command :add do |c|
136
+ c.syntax = 'bro add [COMMAND] [-m MESSAGE]'
137
+ c.summary = 'Add an entry, bro'
138
+ c.description = <<-QQQ.unindent
139
+ This adds an entry to the http://bropages.org database.
140
+
141
+ Called without parameters will add an entry for the last thing you looked up with bro.
142
+ QQQ
143
+ c.example 'Launch your editor to add an entry for curl', 'bro add curl'
144
+ c.example 'Quickly add an entry for curl', 'bro add curl -m "curl http://google.com"'
145
+ # TODO c.option '-m', 'An optional inline entry. This won\'t trigger a system editor to open'
146
+ c.action do |args, options|
147
+ begin
148
+ login_details = state.check_email
149
+ rescue Interrupt, StandardError
150
+ say "Sorry, you can't do this without email verification".sorry
151
+ end
152
+
153
+ unless login_details.nil?
154
+
155
+ cmd = state.get_arg_or_last_command args
156
+
157
+ if cmd.nil?
158
+ say "\nYou must enter a command after #{"bro add".status}.\n\nFor example: #{"bro add".success} #{"curl".success.underline}\n\n"
159
+ else
160
+ prompt = <<-QQQ.unindent
161
+ #~ Bro entry for command '#{cmd}'
162
+ #~ Provide a useful example for how to use '#{cmd}'
163
+ #~ Comments starting with #~ are removed
164
+ #~
165
+ #~ Example for command 'man':
166
+ #~ # Opens up the manual page for the command 'ls'
167
+ #~ man ls
168
+
169
+
170
+ # your_comment_here
171
+ your_command_here
172
+ QQQ
173
+ entry = ask_editor prompt
174
+ if !entry.nil? && entry.gsub(prompt, '').strip.length > 0
175
+ if agree("Submit this entry for #{cmd}? [y/n] ") { |q| q.default = "yes" }
176
+ say "All right, sending your entry...".status
177
+ begin
178
+ RestClient.post URL + '/', login_details.merge({ :entry => { :cmd => cmd, :msg => entry}, :format => 'json', :multipart => true })
179
+ rescue => e
180
+ say e.message
181
+ file = "/tmp/#{cmd}.bro"
182
+
183
+ # increment file name as to not overwrite anything
184
+ i = 1
185
+ while File.exist?(file)
186
+ file = "/tmp/#{cmd}#{i}.bro"
187
+ i += 1
188
+ end
189
+
190
+ # write message to file
191
+ File.open(file, 'w') do |f|
192
+ f.write entry
193
+ end
194
+ say "Woops. There was an error! Your entry was saved to #{file}".problem
195
+ else
196
+ say "Successfully submitted.".success
197
+ end
198
+ end
199
+ else
200
+ say "Canceled. Did not submit entry for '#{cmd}'".status
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end
206
+
207
+ command :lookup do |c|
208
+ c.syntax = 'bro [COMMAND]'
209
+ c.summary = 'Lookup an entry, bro. Or just call bro [COMMAND]'
210
+ c.description = "This looks up entries in the http://bropages.org database."
211
+ c.example 'Look up the bro entries for curl', 'bro curl'
212
+ c.option '--no-color', 'Switch colored output OFF'
213
+ c.option '--with-color', 'Switch colored output ON'
214
+ c.action do |args, options|
215
+ unless options.no_color.nil?
216
+ # set no-color as default
217
+ state.write_state({ :color => Bro::BroState::COLOR_OFF })
218
+ VanillaText.apply
219
+ end
220
+ unless options.with_color.nil?
221
+ # set color as default
222
+ state.write_state({ :color => "" })
223
+ ColoredText.apply
224
+ end
225
+
226
+ if args.empty?
227
+ say <<-QQQ.unindent
228
+ #{"Bro! Specify a command first!".colored.red}
229
+
230
+ \t* For example try #{"bro curl".colored.green}
231
+
232
+ \t* Use #{"bro help".colored.yellow} for more info
233
+
234
+ QQQ
235
+ else
236
+ # the display string for the command
237
+ cmd_display = args.join(" ")
238
+
239
+ # the server argument for the command
240
+ cmd = args.join("%20")
241
+
242
+ state.reset_lookup_ids()
243
+
244
+ # write to ~/.bro file with last command
245
+ state.write_state({ :cmd => cmd_display })
246
+
247
+ # connect to webservice for entry
248
+ error = false
249
+ begin
250
+ res = RestClient.get URL + '/' + cmd + '.json'
251
+ rescue
252
+ say <<-QQQ.unindent
253
+ The #{cmd_display.colored.yellow} command isn't in our database.
254
+
255
+ \t* Typing #{"bro add".colored.green.underline} will let you add #{cmd_display.colored.yellow} to our database!
256
+
257
+ \t* There's nothing to lose by typing #{"bro add".colored.red.underline}, it will just launch an editor with instructions.
258
+
259
+ \t* Need help? Visit #{"http://bropages.org/help".colored.underline}
260
+
261
+ QQQ
262
+ error = true
263
+ end
264
+
265
+ unless error
266
+ enable_paging
267
+ list = JSON.parse res
268
+ s = list.length == 1 ? 'y' : 'ies'
269
+
270
+ say <<-QQQ.unindent
271
+ #{"#{list.length} entr#{s} for #{cmd_display}".status.underline} #{"-- submit your own example with \"bro add #{cmd_display}\"".colored.yellow}
272
+ QQQ
273
+
274
+ i = 0
275
+ list.each {|data|
276
+ i += 1
277
+
278
+ obj = {}
279
+ obj["#{i}"] = data['id']
280
+ state.write_state(obj)
281
+
282
+ lines = data['msg'].split("\n")
283
+
284
+ body = []
285
+ header_found = false
286
+ lines.each_with_index {|line, index|
287
+ line.strip!
288
+ unless line.length == 0
289
+ if starts_with_hashtag(line)
290
+ if index == 0
291
+ line = line_header(line, i)
292
+ header_found = true
293
+ else
294
+ line = line_comment(line)
295
+ end
296
+ else
297
+ if contains_query(line, cmd) or starts_with_dollar(line)
298
+ line = line_cmd(line, cmd, !starts_with_dollar(line))
299
+ else
300
+ # Last resort - assume it's a comment
301
+ line = line_comment(line)
302
+ end
303
+ end
304
+ else
305
+ # Feed a new line
306
+ line = ""
307
+ end
308
+
309
+ body.push line
310
+ }
311
+
312
+ if !header_found
313
+ body.unshift line_header("# Untitled", i)
314
+ end
315
+
316
+ puts "\n" + body.join("\n") + "\n"
317
+ }
318
+
319
+ end
320
+ end
321
+ end
322
+ end
323
+
324
+
325
+ def contains_query(str, query)
326
+ return str.index query
327
+ end
328
+
329
+ def starts_with_dollar(str)
330
+ return /^\s?$/.match(str)
331
+ end
332
+
333
+ def starts_with_hashtag(str)
334
+ return /^\s?#/.match(str)
335
+ end
336
+
337
+ def line_comment(str)
338
+ return "\t# #{str.sub('#', '')}".colored.green
339
+ end
340
+
341
+ def line_cmd(str, highlight, prefix=false)
342
+ if prefix
343
+ str = "$ #{str}"
344
+ end
345
+ return "\t#{str}".gsub highlight, highlight.important
346
+ end
347
+
348
+ def line_header(str, i)
349
+ return str.upcase.colored.yellow.sub /#\s?/, "#{i}. "
350
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wb-bropages
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - bropages.org
8
+ - williamboman
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-03-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json_pure
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 1.8.1
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '='
26
+ - !ruby/object:Gem::Version
27
+ version: 1.8.1
28
+ - !ruby/object:Gem::Dependency
29
+ name: commander
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '='
33
+ - !ruby/object:Gem::Version
34
+ version: 4.1.5
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '='
40
+ - !ruby/object:Gem::Version
41
+ version: 4.1.5
42
+ - !ruby/object:Gem::Dependency
43
+ name: rest-client
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: smart_colored
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: highline
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '='
75
+ - !ruby/object:Gem::Version
76
+ version: 1.6.20
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '='
82
+ - !ruby/object:Gem::Version
83
+ version: 1.6.20
84
+ - !ruby/object:Gem::Dependency
85
+ name: mime-types
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: 1.19.0
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: 1.19.0
98
+ description: Highly readable supplement to man pages. Shows simple, concise examples
99
+ for unix commands.
100
+ email: william@redwill.se
101
+ executables:
102
+ - bro
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - bin/bro
107
+ - lib/bro.rb
108
+ - lib/bro/bro_state.rb
109
+ - lib/bro/state.rb
110
+ - lib/bro/string_hacks.rb
111
+ - lib/bro/version.rb
112
+ homepage: https://github.com/williamboman/bro
113
+ licenses: []
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.4.6
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Bro. Forked.
135
+ test_files: []