hookapp 0.0.3 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/CHANGELOG.md +32 -0
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +62 -28
  6. data/LICENSE.md +31 -0
  7. data/OVERVIEW.md +80 -0
  8. data/README.md +286 -23
  9. data/Rakefile +1 -1
  10. data/bin/hook +153 -20
  11. data/buildnotes.md +29 -0
  12. data/hook.rdoc +90 -9
  13. data/hookapp.gemspec +9 -8
  14. data/html/App.html +119 -0
  15. data/html/GLI.html +99 -0
  16. data/html/GLI/Commands.html +99 -0
  17. data/html/GLI/Commands/Doc.html +99 -0
  18. data/html/GLI/Commands/MarkdownDocumentListener.html +717 -0
  19. data/html/Hook.html +113 -0
  20. data/html/HookApp.html +1222 -0
  21. data/html/Hooker.html +119 -0
  22. data/html/README_rdoc.html +328 -0
  23. data/html/String.html +427 -0
  24. data/html/created.rid +9 -0
  25. data/html/css/fonts.css +167 -0
  26. data/html/css/rdoc.css +619 -0
  27. data/html/fonts/Lato-Light.ttf +0 -0
  28. data/html/fonts/Lato-LightItalic.ttf +0 -0
  29. data/html/fonts/Lato-Regular.ttf +0 -0
  30. data/html/fonts/Lato-RegularItalic.ttf +0 -0
  31. data/html/fonts/SourceCodePro-Bold.ttf +0 -0
  32. data/html/fonts/SourceCodePro-Regular.ttf +0 -0
  33. data/html/images/add.png +0 -0
  34. data/html/images/arrow_up.png +0 -0
  35. data/html/images/brick.png +0 -0
  36. data/html/images/brick_link.png +0 -0
  37. data/html/images/bug.png +0 -0
  38. data/html/images/bullet_black.png +0 -0
  39. data/html/images/bullet_toggle_minus.png +0 -0
  40. data/html/images/bullet_toggle_plus.png +0 -0
  41. data/html/images/date.png +0 -0
  42. data/html/images/delete.png +0 -0
  43. data/html/images/find.png +0 -0
  44. data/html/images/loadingAnimation.gif +0 -0
  45. data/html/images/macFFBgHack.png +0 -0
  46. data/html/images/package.png +0 -0
  47. data/html/images/page_green.png +0 -0
  48. data/html/images/page_white_text.png +0 -0
  49. data/html/images/page_white_width.png +0 -0
  50. data/html/images/plugin.png +0 -0
  51. data/html/images/ruby.png +0 -0
  52. data/html/images/tag_blue.png +0 -0
  53. data/html/images/tag_green.png +0 -0
  54. data/html/images/transparent.png +0 -0
  55. data/html/images/wrench.png +0 -0
  56. data/html/images/wrench_orange.png +0 -0
  57. data/html/images/zoom.png +0 -0
  58. data/html/index.html +308 -0
  59. data/html/js/darkfish.js +84 -0
  60. data/html/js/navigation.js +105 -0
  61. data/html/js/navigation.js.gz +0 -0
  62. data/html/js/search.js +110 -0
  63. data/html/js/search_index.js +1 -0
  64. data/html/js/search_index.js.gz +0 -0
  65. data/html/js/searcher.js +229 -0
  66. data/html/js/searcher.js.gz +0 -0
  67. data/html/table_of_contents.html +409 -0
  68. data/lib/completion/hook_completion.bash +22 -0
  69. data/lib/completion/hook_completion.fish +31 -0
  70. data/lib/completion/hook_completion.zsh +22 -0
  71. data/lib/helpers/fuzzyfilefinder +0 -0
  72. data/lib/hook.rb +5 -1
  73. data/lib/hook/hookapp.rb +489 -0
  74. data/lib/hook/hooker.rb +1 -308
  75. data/lib/hook/markdown_document_listener.rb +164 -0
  76. data/lib/hook/string.rb +60 -0
  77. data/lib/hook/version.rb +3 -1
  78. metadata +87 -22
@@ -1,313 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # String helpers
4
- class String
5
- def split_hook
6
- elements = split(/\|\|/)
7
- {
8
- name: elements[0],
9
- url: elements[1],
10
- path: elements[2]
11
- }
12
- end
13
-
14
- def split_hooks
15
- split(/\^\^/).map(&:split_hook)
16
- end
17
-
18
- def valid_hook
19
- if File.exist?(self)
20
- File.expand_path(self)
21
- elsif self =~ /\S+:\/\//
22
- self
23
- else
24
- if self =~ /^\[.*?\]\((.*?)\)$/
25
- mdlink = $1
26
- mdlink.valid_hook
27
- else
28
- nil
29
- end
30
- end
31
- end
32
-
33
- def valid_hook!
34
- replace valid_hook
35
- end
36
- end
37
-
38
3
  # Hook.app CLI interface
39
4
  class Hooker
40
- def initialize(global_args)
41
- @global_args = global_args
42
- end
43
-
44
- def validate_format(fmt, options)
45
- valid_format_rx = options.map { |fmt| fmt.sub(/^(.)(.*)$/, '^\1(\2)?$') }
46
- valid_format = false
47
- valid_format_rx.each_with_index do |rx, i|
48
- cmp = Regexp.new(rx, 'i')
49
- next unless fmt =~ cmp
50
- valid_format = options[i]
51
- break
52
- end
53
- return valid_format
54
- end
55
-
56
- def bookmark_for(url)
57
- url.valid_hook!
58
- raise "Invalid target: #{url}" unless url
59
-
60
- mark = `osascript <<'APPLESCRIPT'
61
- tell application "Hook"
62
- set _hook to bookmark from URL "#{url}"
63
- return title of _hook & "||" & address of _hook & "||" & path of _hook
64
- end tell
65
- APPLESCRIPT`.strip
66
- mark.split_hook
67
- end
68
-
69
- def get_hooks(url)
70
- url.valid_hook!
71
- raise "Invalid target: #{url}" unless url
72
-
73
- hooks = `osascript <<'APPLESCRIPT'
74
- tell application "Hook"
75
- set _mark to bookmark from URL "#{url}"
76
- if _mark is {} then return ""
77
- set _hooks to bookmarks hooked to _mark
78
- set _out to {}
79
- repeat with _hook in _hooks
80
- set _out to _out & (title of _hook & "||" & address of _hook & "||" & path of _hook)
81
- end repeat
82
- set {astid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "^^"}
83
- set _output to _out as string
84
- set AppleScript's text item delimiters to astid
85
- return _output
86
- end tell
87
- APPLESCRIPT`.strip
88
- hooks.split_hooks
89
- end
90
-
91
- def copy_bookmark(url, opts)
92
- mark = bookmark_for(url)
93
- output = if opts[:markdown]
94
- "[#{mark[:name]}](#{mark[:url]})"
95
- else
96
- mark[:url]
97
- end
98
- `/bin/echo -n #{Shellwords.escape(output)} | pbcopy`
99
- %(Copied #{opts[:markdown] ? 'Markdown link' : 'Hook URL'} for '#{mark[:name]}' to clipboard)
100
- end
101
-
102
- def select_hook(marks)
103
- intpad = marks.length.to_s.length + 1
104
- marks.each_with_index do |mark, i|
105
- STDERR.printf "%#{intpad}d) %s\n", i + 1, mark[:name]
106
- end
107
- STDERR.print 'Open which bookmark: '
108
- sel = STDIN.gets.strip.to_i
109
- if sel.positive? && sel <= marks.length
110
- marks[sel - 1]
111
- else
112
- warn 'Invalid selection'
113
- Process.exit 1
114
- end
115
- end
116
-
117
- def open_gui(url)
118
- `osascript <<'APPLESCRIPT'
119
- tell application "Hook"
120
- set _mark to bookmark from URL "#{url.valid_hook}"
121
- invoke on _mark
122
- end tell
123
- APPLESCRIPT`
124
- end
125
-
126
- def open_linked(url)
127
- marks = get_hooks(url)
128
- if marks.empty?
129
- warn "No hooks found for #{url}"
130
- else
131
- res = select_hook(marks)
132
- `open '#{res[:url]}'`
133
- end
134
- end
135
-
136
- def link_files(args)
137
- target = args.pop
138
- target.valid_hook!
139
- raise "Invalid target: #{target}" unless target
140
-
141
- args.each do |file|
142
- file.valid_hook!
143
- raise "Invalid target: #{file}" unless file
144
-
145
- puts "Linking #{file} and #{target}..."
146
- `osascript <<'APPLESCRIPT'
147
- tell application "Hook"
148
- set _mark1 to bookmark from URL "#{file}"
149
- set _mark2 to bookmark from URL "#{target}"
150
- hook together _mark1 and _mark2
151
- return true
152
- end tell
153
- APPLESCRIPT`
154
- end
155
- "Linked #{args.length} files to #{target}"
156
- end
157
-
158
- def clone_hooks(args)
159
- target = args.pop.valid_hook
160
- source = args[0].valid_hook
161
-
162
- if target && source
163
- hooks = get_hooks(source)
164
- hooks.each do |hook|
165
- `osascript <<'APPLESCRIPT'
166
- tell application "Hook"
167
- set _mark1 to bookmark from URL "#{hook[:url]}"
168
- set _mark2 to bookmark from URL "#{target}"
169
- hook together _mark1 and _mark2
170
- return true
171
- end tell
172
- APPLESCRIPT`
173
- end
174
- "Hooks from #{source} cloned to #{target}"
175
- else
176
- raise 'Invalid file specified'
177
- end
178
- end
179
-
180
- def delete_all_hooks(url)
181
- STDERR.print "Are you sure you want to delete ALL hooks from #{url} (y/N)? "
182
- res = STDIN.gets.strip
183
- if res =~ /^y/i
184
- get_hooks(url).each do |hook|
185
- `osascript <<'APPLESCRIPT'
186
- tell application "Hook"
187
- set _mark1 to bookmark from URL "#{hook[:url]}"
188
- set _mark2 to bookmark from URL "#{url}"
189
- remove hook between _mark1 and _mark2
190
- return true
191
- end tell
192
- APPLESCRIPT`
193
- end
194
- "Removed all hooks from #{url}"
195
- end
196
- end
197
-
198
- def delete_hooks(args, opts)
199
- urls = args.map(&:valid_hook).delete_if { |url| !url }
200
- output = []
201
- if opts[:all]
202
- urls.each_with_index do |url, i|
203
- raise "Invalid target: #{args[i]}" unless url
204
-
205
- output.push(delete_all_hooks(url))
206
- end
207
- return output.join("\n")
208
- end
209
-
210
- if urls.length == 2
211
- source = urls[0]
212
- target = urls[1]
213
- `osascript <<'APPLESCRIPT'
214
- tell application "Hook"
215
- set _mark1 to bookmark from URL "#{source}"
216
- set _mark2 to bookmark from URL "#{target}"
217
- remove hook between _mark1 and _mark2
218
- return true
219
- end tell
220
- APPLESCRIPT`
221
- return "Hook removed between #{source} and #{target}"
222
- else
223
- raise "Invalid number of URLs or files specified"
224
-
225
- end
226
- end
227
-
228
- def link_all(args)
229
- args.each do |file|
230
- source = file.valid_hook
231
- link_to = args.dup.map(&:valid_url).reject { |url|
232
- url == source
233
- }
234
- link_to.each do |url|
235
- `osascript <<'APPLESCRIPT'
236
- tell application "Hook"
237
- set _mark1 to bookmark from URL "#{source}"
238
- set _mark2 to bookmark from URL "#{url}"
239
- hook together _mark1 and _mark2
240
- return true
241
- end tell
242
- APPLESCRIPT`
243
- end
244
- end
245
- "Linked #{args.length} files to each other"
246
- end
247
-
248
- def linked_bookmarks(args, opts)
249
- result = []
250
-
251
- separator = args.length == 1 && opts[:format] == 'paths' && opts[:null_separator] ? "\0" : "\n"
252
-
253
- args.each do |url|
254
- source_mark = bookmark_for(url)
255
- filename = source_mark[:name]
256
-
257
- case opts[:format]
258
- when /^m/
259
- filename = "[#{source_mark[:name]}](#{source_mark[:url]})"
260
- filename += " <file://#{CGI.escape(source_mark[:path])}>" if source_mark[:path]
261
- when /^p/
262
- filename = "File: #{source_mark[:name]}"
263
- filename += " (#{source_mark[:path]})" if source_mark[:path]
264
- when /^h/
265
- filename = "File: #{source_mark[:name]}"
266
- filename += " (#{source_mark[:url]})" if source_mark[:url]
267
- else
268
- filename = "Bookmarks attached to #{source_mark[:path] || source_mark[:url]}"
269
- end
270
-
271
- hooks_arr = get_hooks(url)
272
-
273
- if !hooks_arr.empty?
274
- hooks_arr.reject! { |h| h[:path].nil? || h[:path] == '' } if opts[:files_only]
275
-
276
- output = []
277
-
278
- case opts[:format]
279
- when /^m/
280
- hooks_arr.each do |h|
281
- output.push("- [#{h[:name]}](#{h[:url]})")
282
- end
283
- when /^p/
284
- hooks_arr.each do |h|
285
- output.push(h[:path].nil? ? h[:url] : h[:path])
286
- end
287
- when /^h/
288
- hooks_arr.each do |h|
289
- output.push(h[:url])
290
- end
291
- else
292
- hooks_arr.each do |h|
293
- output.push("Title: #{h[:name]}\nPath: #{h[:path]}\nAddress: #{h[:url]}\n---------------------")
294
- end
295
- end
296
- else
297
- output = ['No bookmarks']
298
- end
299
- result.push({ file: filename, links: output.join(separator) })
300
- end
301
-
302
- if result.length > 1 || opts[:format] == 'verbose'
303
- result.map! do |res|
304
- "#{res[:file]}\n\n#{res[:links]}\n"
305
- end
306
- else
307
- result.map! do |res|
308
- res[:links]
309
- end
310
- end
311
- result.join(separator)
312
- end
5
+ include HookApp
313
6
  end
@@ -0,0 +1,164 @@
1
+ require 'stringio'
2
+ require 'time'
3
+ require 'fileutils'
4
+
5
+ module GLI
6
+ module Commands
7
+ # DocumentListener class for GLI documentation generator
8
+ class MarkdownDocumentListener
9
+ def initialize(_global_options, _options, _arguments, app)
10
+ @exe = app.exe_name
11
+ if File.exist?('README.md') # Back up existing README
12
+ FileUtils.mv('README.md', 'README.bak')
13
+ $stderr.puts "Backing up existing README.md to README.bak"
14
+ end
15
+ @io = File.new('README.md', 'w')
16
+ @nest = '#'
17
+ @arg_name_formatter = GLI::Commands::HelpModules::ArgNameFormatter.new
18
+ end
19
+
20
+ def beginning
21
+ end
22
+
23
+ # Called when processing has completed
24
+ def ending
25
+ if File.exist?('CREDITS.md')
26
+ @io.puts IO.read('CREDITS.md')
27
+ @io.puts
28
+ end
29
+ if File.exist?('LICENSE.md')
30
+ @io.puts IO.read('LICENSE.md')
31
+ @io.puts
32
+ end
33
+ @io.puts
34
+ @io.puts "Documentation generated #{Time.now.strftime('%Y-%m-%d %H:%M')}"
35
+ @io.puts
36
+ @io.close
37
+ end
38
+
39
+ # Gives you the program description
40
+ def program_desc(desc)
41
+ @io.puts "# #{@exe} CLI"
42
+ @io.puts
43
+ @io.puts desc
44
+ @io.puts
45
+ end
46
+
47
+ def program_long_desc(desc)
48
+ @io.puts "> #{desc}"
49
+ @io.puts
50
+ end
51
+
52
+ # Gives you the program version
53
+ def version(version)
54
+ @io.puts "*v#{version}*"
55
+ @io.puts
56
+ # Hacking in the overview file
57
+ if File.exist?('OVERVIEW.md')
58
+ @io.puts IO.read('OVERVIEW.md')
59
+ @io.puts
60
+ end
61
+ end
62
+
63
+ def options
64
+ if @nest.size == 1
65
+ @io.puts "## Global Options"
66
+ else
67
+ @io.puts header("Options", 1)
68
+ end
69
+ @io.puts
70
+ end
71
+
72
+ # Gives you a flag in the current context
73
+ def flag(name, aliases, desc, long_desc, default_value, arg_name, must_match, _type)
74
+ invocations = ([name] + Array(aliases)).map { |_| "`" + add_dashes(_) + "`" }.join(' | ')
75
+ usage = "#{invocations} #{arg_name || 'arg'}"
76
+ @io.puts header(usage, 2)
77
+ @io.puts
78
+ @io.puts String(desc).strip
79
+ @io.puts "\n*Default Value:* `#{default_value || 'None'}`\n" unless default_value.nil?
80
+ @io.puts "\n*Must Match:* `#{must_match.to_s}`\n" unless must_match.nil?
81
+ cmd_desc = String(long_desc).strip
82
+ @io.puts "> #{cmd_desc}\n" unless cmd_desc.length == 0
83
+ @io.puts
84
+ end
85
+
86
+ # Gives you a switch in the current context
87
+ def switch(name, aliases, desc, long_desc, negatable)
88
+ if negatable
89
+ name = "[no-]#{name}" if name.to_s.length > 1
90
+ aliases = aliases.map { |_| _.to_s.length > 1 ? "[no-]#{_}" : _ }
91
+ end
92
+ invocations = ([name] + aliases).map { |_| "`" + add_dashes(_) + "`" }.join('|')
93
+ @io.puts header("#{invocations}", 2)
94
+ @io.puts
95
+ @io.puts String(desc).strip
96
+ cmd_desc = String(long_desc).strip
97
+ @io.puts "\n> #{cmd_desc}\n" unless cmd_desc.length == 0
98
+ @io.puts
99
+ end
100
+
101
+ def end_options
102
+ end
103
+
104
+ def commands
105
+ @io.puts header("Commands", 1)
106
+ @io.puts
107
+ increment_nest
108
+ end
109
+
110
+ # Gives you a command in the current context and creates a new context of this command
111
+ def command(name, aliases, desc, long_desc, arg_name, arg_options)
112
+ arg_name_fmt = @arg_name_formatter.format(arg_name, arg_options, [])
113
+ @io.puts header("`$ #{@exe}` <mark>`#{([name] + aliases).join('|')}`</mark> `#{arg_name_fmt}`", 1)
114
+ @io.puts
115
+ @io.puts "*#{String(desc).strip}*"
116
+ @io.puts
117
+ cmd_desc = String(long_desc).strip.split("\n").map { |_| "> #{_}" }.join("\n")
118
+ @io.puts "#{cmd_desc}\n\n" unless cmd_desc.length == 0
119
+ increment_nest
120
+ end
121
+
122
+ # Ends a command, and "pops" you back up one context
123
+ def end_command(_name)
124
+ decrement_nest
125
+ @io.puts "* * * * * *\n\n" unless @nest.size > 2
126
+ end
127
+
128
+ # Gives you the name of the current command in the current context
129
+ def default_command(name)
130
+ @io.puts "#### [Default Command] #{name}" unless name.nil?
131
+ end
132
+
133
+ def end_commands
134
+ decrement_nest
135
+ end
136
+
137
+ private
138
+
139
+ def add_dashes(name)
140
+ name = "-#{name}"
141
+ name = "-#{name}" if name.length > 2
142
+ name
143
+ end
144
+
145
+ def header(content, increment)
146
+ if @nest.size + increment > 6
147
+ "**#{content}**"
148
+ else
149
+ "#{@nest}#{'#'*increment} #{content}"
150
+ end
151
+ end
152
+
153
+ def increment_nest(increment=1)
154
+ @nest = "#{@nest}#{'#'*increment}"
155
+ end
156
+
157
+ def decrement_nest(increment=1)
158
+ @nest.gsub!(/#{'#'*increment}$/, '')
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ GLI::Commands::Doc::FORMATS['markdown'] = GLI::Commands::MarkdownDocumentListener