wb-bropages 1.0.0

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 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: []