rundoc 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +8 -0
  3. data/CHANGELOG.md +3 -0
  4. data/Gemfile +1 -0
  5. data/README.md +63 -15
  6. data/bin/rundoc +8 -0
  7. data/lib/rundoc.rb +14 -1
  8. data/lib/rundoc/code_command.rb +18 -4
  9. data/lib/rundoc/code_command/background.rb +9 -0
  10. data/lib/rundoc/code_command/background/log/clear.rb +17 -0
  11. data/lib/rundoc/code_command/background/log/read.rb +16 -0
  12. data/lib/rundoc/code_command/background/process_spawn.rb +70 -0
  13. data/lib/rundoc/code_command/background/start.rb +36 -0
  14. data/lib/rundoc/code_command/background/stop.rb +17 -0
  15. data/lib/rundoc/code_command/background/wait.rb +19 -0
  16. data/lib/rundoc/code_command/bash.rb +1 -1
  17. data/lib/rundoc/code_command/bash/cd.rb +1 -1
  18. data/lib/rundoc/code_command/file_command/append.rb +2 -0
  19. data/lib/rundoc/code_command/raw.rb +18 -0
  20. data/lib/rundoc/code_command/rundoc_command.rb +2 -1
  21. data/lib/rundoc/code_section.rb +21 -74
  22. data/lib/rundoc/peg_parser.rb +282 -0
  23. data/lib/rundoc/version.rb +1 -1
  24. data/rundoc.gemspec +2 -1
  25. data/test/fixtures/rails_5/rundoc.md +70 -74
  26. data/test/rundoc/code_commands/append_file_test.rb +2 -2
  27. data/test/rundoc/code_commands/background_test.rb +43 -0
  28. data/test/rundoc/code_commands/bash_test.rb +1 -1
  29. data/test/rundoc/code_commands/pipe_test.rb +1 -1
  30. data/test/rundoc/code_commands/remove_contents_test.rb +1 -1
  31. data/test/rundoc/code_section_test.rb +6 -5
  32. data/test/rundoc/parser_test.rb +2 -7
  33. data/test/rundoc/peg_parser_test.rb +348 -0
  34. data/test/rundoc/regex_test.rb +1 -1
  35. data/test/rundoc/test_parse_java.rb +1 -1
  36. data/test/test_helper.rb +1 -1
  37. metadata +33 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7935527c5d717e2c4bdc0883a285dd3c7f834f65
4
- data.tar.gz: ffc9bf341d82df737a5dc3ba4bb557160ae049b9
2
+ SHA256:
3
+ metadata.gz: ed87bdf4593dcd65e6823a9ef5231802b0282aed932c119022cfc44d2ec6f9d8
4
+ data.tar.gz: 0d7a80aab3b225049978eb30ca301f817203a564aa9787dcd0026a89b61c101d
5
5
  SHA512:
6
- metadata.gz: e4839a376fc7911464bfd37ec2a64cc824963a52bef72d1e9e4876c07c8e1f5d6d1d99bab48243ef1c769cb98dabf186624dfe4ecf5a411480a6a748fd0293ab
7
- data.tar.gz: 6cd4c38c55413efe85e174b561f39e99bc5788d21e2f63e93cef0c709563609a3864f704cb05c8c04b139d999ef789addeda7105b0b71c8f524890cc4aad2a4d
6
+ metadata.gz: ff4a68baac0e70330af729e752dc96e01c95e1da4ffe0e4850d8fca619e026adbaea940fed31982d41bcc41308ffdb7c3625145c2209ea0db7ec22b714738377
7
+ data.tar.gz: '09e9a757c31ea81c31b1e1d1c70da5241f2b756c39a2f6701e0d4b9f2a108647d21fb6d40edd31417b5136f3eb72f802c03020b7af9d42677d8f6efd96e3bf4d'
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.4
4
+
5
+ sudo: false
6
+
7
+ script: bundle exec rake test
8
+
@@ -0,0 +1,3 @@
1
+ ## 1.0.0
2
+
3
+ - Now using a propper PEG parser (parslet)
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
1
  source "http://rubygems.org"
2
+ gem 'm'
2
3
 
3
4
  gemspec
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # RunDOC
2
2
 
3
- ![](https://www.dropbox.com/s/u354td51brynr4h/Screenshot%202017-05-09%2009.36.33.png?dl=1)
3
+ ![](https://www.dropbox.com/s/u354td51brynr4h/Screenshot%202017-05-09%2009.36.33.png?raw=1)
4
4
 
5
5
  ## What
6
6
 
@@ -55,10 +55,22 @@ Run the `rundoc build` command on any markdown file
55
55
  $ rundoc build --path runDOC.md
56
56
  ```
57
57
 
58
- Note: This command will create and manipulate directories in the working directory of your source markdown file. Best practice is to have your source markdown file in it's own empty directory.
58
+ Note: This command will create and manipulate directories in the working directory of your source markdown file. Best practice is to have your source markdown file in its own empty directory.
59
59
 
60
60
  This will generate a project folder with your project in it, and a markdown README.md with the parsed output of the markdown docs, and a copy of the source.
61
61
 
62
+ ## Quick docs
63
+
64
+ - [$]()
65
+ - [fail.$]()
66
+ - [file.write]()
67
+ - [file.append]()
68
+ - [file.remove]()
69
+ - [background.start]()
70
+ - [background.stop]()
71
+ - [background.log.read]()
72
+ - [background.log.clear]()
73
+
62
74
  ## Write it:
63
75
 
64
76
  Rundoc uses github flavored markdown. This means you write like normal but in your code sections
@@ -69,7 +81,7 @@ All runDOC commands are prefixed with three colons `:::` and are inclosed in a c
69
81
  command such as `$` which is an alias for `bash` commands like this:
70
82
 
71
83
  ```
72
- :::> $ git init .
84
+ :::>- $ git init .
73
85
  ```
74
86
 
75
87
  Nothing before the three colons matters. The space between the colons
@@ -80,7 +92,7 @@ can add a minus symbol `-` to the end to prevent it from being
80
92
  rendered.
81
93
 
82
94
  ```
83
- :::- $ git init .
95
+ :::-- $ git init .
84
96
  ```
85
97
 
86
98
  > Note: If all commands inside of a code block are hidden, the entire codeblock will not be rendered.
@@ -107,9 +119,9 @@ That's the syntax, let's look at different runDOC commands
107
119
  An arrow `>` is shorthand for "render this" and a dash `-` is shorthand for skip this section. The posions two positions are command first and result second. You can skip a trailing `-`.
108
120
 
109
121
 
110
- - `:::>` (yes command, not result)
122
+ - `:::>-` (yes command, not result)
111
123
  - `:::>>` (yes command, yes result)
112
- - `:::-` (not command, not result)
124
+ - `:::--` (not command, not result)
113
125
  - `:::->` (not command, yes result)
114
126
 
115
127
  ## Shell Commands
@@ -179,10 +191,12 @@ Current Commands:
179
191
  - `file.append`
180
192
  - `file.remove`
181
193
 
194
+ If the exact filename is not known you can use a [file glob (\*)](https://github.com/schneems/rundoc/pull/6).
195
+
182
196
  Use the `file.write` keyword followed by a filename, on the next line(s) put the contents of the file
183
197
 
184
198
  ```
185
- :::> file.write config/routes.rb
199
+ :::>- file.write config/routes.rb
186
200
 
187
201
  Example::Application.routes.draw do
188
202
  root :to => "pages#index"
@@ -196,7 +210,7 @@ Use the `file.write` keyword followed by a filename, on the next line(s) put the
196
210
  If you wanted to change `users` to `products` you could write to the same file again.
197
211
 
198
212
  ```
199
- :::> file.write config/routes.rb
213
+ :::>- file.write config/routes.rb
200
214
  Example::Application.routes.draw do
201
215
  root :to => "pages#index"
202
216
 
@@ -256,13 +270,47 @@ Anything after the pipe `|` will generate a new command with the output of the p
256
270
 
257
271
  This command is currently hacked together, and needs a refactor. Use it, but if something does not behave as you would expected open an issue and explain it.
258
272
 
273
+ ## Background
274
+
275
+ Sometimes you want to start a long lived process like a server in the background. In that case, the `background` namespace has your, well, back.
276
+
277
+ To start a process, pass in the command as the first arg, and give it a name (so it can be referenced later):
278
+
279
+ ```
280
+ :::>> background.start("rails server", name: "server")
281
+ ```
282
+
283
+ You can make the background process wait until it receives a certain string in the logs. For instance to make sure that the server is fully booted:
284
+
285
+ ```
286
+ :::>> background.start("rails server", name: "server", wait: "Listening on")
287
+ ```
288
+
289
+ You can stop the process by referencing the name:
290
+
291
+ ```
292
+ :::-- background.stop(name: "server")
293
+ ```
294
+
295
+ You can also get the log contents:
296
+
297
+
298
+ ```
299
+ :::>> background.log.read(name: "server")
300
+ ```
301
+
302
+ You can also truncate the logs:
303
+
304
+ ```
305
+ :::>> background.log.clear(name: "server")
306
+ ```
259
307
 
260
308
  ## Configure
261
309
 
262
310
  You can configure your docs in your docs use the `runDOC` command
263
311
 
264
312
  ```
265
- :::- rundoc
313
+ :::-- rundoc
266
314
  ```
267
315
 
268
316
  Note: Make sure you run this as a hidden command (with `-`).
@@ -273,7 +321,7 @@ This will eval any code you put under that line (in Ruby). If you want to run so
273
321
 
274
322
 
275
323
  ```
276
- :::- rundoc
324
+ :::-- rundoc
277
325
  Rundoc.configure do |config|
278
326
  config.after_build do
279
327
  puts "you could push to github here"
@@ -289,7 +337,7 @@ This will eval any code you put under that line (in Ruby). If you want to run so
289
337
  By default your app builds in a `tmp` directory. If any failures occur the results will remain in `tmp`. On a successful build the contents are copied over to `project`. If you are generating a new rails project in your code `$ rails new myapp`. Then the finished directory would be in `project/myapp`. If you don't like the `./project` prefix you could tell runDOC to output contents in `./myapp` instead.
290
338
 
291
339
  ```
292
- :::- rundoc
340
+ :::-- rundoc
293
341
  Rundoc.configure do |config|
294
342
  config.project_root = "myapp"
295
343
  end
@@ -302,7 +350,7 @@ This will also be the root directory that the `after_build` is executed in.
302
350
  Sometimes sensitive info like usernames, email addresses, or passwords may be introduced to the output readme. Let's say that your email address was `schneems@example.com` you could filter this out of your final document and replace it with `developer@example.com` instead like this:
303
351
 
304
352
  ```
305
- :::- rundoc
353
+ :::-- rundoc
306
354
  Rundoc.configure do |config|
307
355
  config.filter_sensitive("schneems@exmaple.com" => "developer@example.com")
308
356
  end
@@ -323,13 +371,13 @@ This is a section for brainstorming. If it's here it's not guaranteed to get wor
323
371
 
324
372
 
325
373
  ```
326
- :::> background.start(command: "rails server")
374
+ :::>- background.start(command: "rails server")
327
375
  ```
328
376
 
329
377
  ```
330
378
  :::>> background.read("rails server")
331
- :::> | $ head -n 23
332
- :::> background.clear
379
+ :::>- | $ head -n 23
380
+ :::>- background.clear
333
381
  ```
334
382
 
335
383
 
data/bin/rundoc CHANGED
@@ -84,6 +84,14 @@ class RundocCLI < Thor
84
84
  Dir.chdir(project_dir) do
85
85
  Rundoc.run_after_build
86
86
  end
87
+
88
+ ensure
89
+ Rundoc::CodeCommand::Background::ProcessSpawn.tasks.each do |name, task|
90
+ next unless task.alive?
91
+
92
+ puts "Warning background task is still running, cleaning up: name: #{name}"
93
+ task.stop
94
+ end
87
95
  end
88
96
  end
89
97
 
@@ -7,9 +7,21 @@ module Rundoc
7
7
 
8
8
  def code_command_from_keyword(keyword, args)
9
9
  klass = code_command(keyword.to_sym) || Rundoc::CodeCommand::NoSuchCommand
10
- cc = klass.new(args)
10
+ original_args = args.dup
11
+ if args.is_a?(Array) && args.last.is_a?(Hash)
12
+ kwargs = args.pop
13
+ cc = klass.new(*args, **kwargs)
14
+ elsif args.is_a?(Hash)
15
+ cc = klass.new(**args)
16
+ else
17
+ cc = klass.new(*args)
18
+ end
19
+
20
+ cc.original_args = original_args
11
21
  cc.keyword = keyword
12
22
  cc
23
+ rescue ArgumentError => e
24
+ raise ArgumentError, "Wrong method signature for #{keyword} with arguments: #{original_args.inspect}, error:\n #{e.message}"
13
25
  end
14
26
 
15
27
  def parser_options
@@ -74,3 +86,4 @@ end
74
86
  require 'rundoc/parser'
75
87
  require 'rundoc/code_section'
76
88
  require 'rundoc/code_command'
89
+ require 'rundoc/peg_parser'
@@ -1,10 +1,15 @@
1
1
  module Rundoc
2
+ # Generic CodeCommand class to be inherited
3
+ #
2
4
  class CodeCommand
3
- attr_accessor :render_result, :render_command, :command, :contents, :keyword
5
+ attr_accessor :render_result, :render_command,
6
+ :command, :contents, :keyword,
7
+ :original_args
8
+
4
9
  alias :render_result? :render_result
5
10
  alias :render_command? :render_command
6
11
 
7
- def initialize(arg)
12
+ def initialize(*args)
8
13
  end
9
14
 
10
15
  def hidden?
@@ -21,16 +26,25 @@ module Rundoc
21
26
  end
22
27
  alias :<< :push
23
28
 
24
- # executes command to build project
29
+ # Executes command to build project
30
+ # Is expected to return the result of the command
25
31
  def call(env = {})
26
32
  raise "not implemented"
27
33
  end
34
+
35
+ # the output of the command, i.e. `$ cat foo.txt`
36
+ def to_md(env = {})
37
+ raise "not implemented"
38
+ end
28
39
  end
29
40
  end
30
41
 
42
+
31
43
  require 'rundoc/code_command/bash'
32
44
  require 'rundoc/code_command/pipe'
33
45
  require 'rundoc/code_command/write'
34
46
  require 'rundoc/code_command/repl'
35
47
  require 'rundoc/code_command/rundoc_command'
36
- require 'rundoc/code_command/no_such_command'
48
+ require 'rundoc/code_command/no_such_command'
49
+ require 'rundoc/code_command/raw'
50
+ require 'rundoc/code_command/background'
@@ -0,0 +1,9 @@
1
+ class Rundoc::CodeCommand::Background
2
+ end
3
+
4
+ require 'rundoc/code_command/background/process_spawn'
5
+ require 'rundoc/code_command/background/start'
6
+ require 'rundoc/code_command/background/stop'
7
+ require 'rundoc/code_command/background/wait'
8
+ require 'rundoc/code_command/background/log/clear'
9
+ require 'rundoc/code_command/background/log/read'
@@ -0,0 +1,17 @@
1
+ class Rundoc::CodeCommand::Background::Log
2
+ class Clear < Rundoc::CodeCommand
3
+ def initialize(name: )
4
+ @spawn = Rundoc::CodeCommand::Background::ProcessSpawn.find(name)
5
+ end
6
+
7
+ def to_md(env = {})
8
+ ""
9
+ end
10
+
11
+ def call(env = {})
12
+ @spawn.log.truncate(0)
13
+ ""
14
+ end
15
+ end
16
+ end
17
+ Rundoc.register_code_command(:"background.log.clear", Rundoc::CodeCommand::Background::Log::Clear)
@@ -0,0 +1,16 @@
1
+ class Rundoc::CodeCommand::Background::Log
2
+ class Read < Rundoc::CodeCommand
3
+ def initialize(name: )
4
+ @spawn = Rundoc::CodeCommand::Background::ProcessSpawn.find(name)
5
+ end
6
+
7
+ def to_md(env = {})
8
+ ""
9
+ end
10
+
11
+ def call(env = {})
12
+ @spawn.log.read
13
+ end
14
+ end
15
+ end
16
+ Rundoc.register_code_command(:"background.log.read", Rundoc::CodeCommand::Background::Log::Read)
@@ -0,0 +1,70 @@
1
+ require 'shellwords'
2
+ require 'timeout'
3
+
4
+ class Rundoc::CodeCommand::Background
5
+ class ProcessSpawn
6
+ def self.tasks
7
+ @tasks
8
+ end
9
+
10
+ @tasks = {}
11
+ def self.add(name, value)
12
+ raise "Task named #{name.inspect} is already started, choose a different name" if @tasks[name]
13
+ @tasks[name] = value
14
+ end
15
+
16
+ def self.find(name)
17
+ raise "Could not find task with name #{name.inspect}, known task names: #{@tasks.keys.inspect}" unless @tasks[name]
18
+ @tasks[name]
19
+ end
20
+
21
+ attr_reader :log, :pid
22
+
23
+ def initialize(command , timeout: 5, log: Tempfile.new("log"), out: "2>&1")
24
+ @command = command
25
+ @timeout_value = timeout
26
+ @log = log
27
+
28
+ @log = Pathname.new(@log)
29
+ @log.dirname.mkpath
30
+
31
+ @command = "/usr/bin/env bash -c #{@command.shellescape} >> #{@log} #{out}"
32
+ @pid = nil
33
+ end
34
+
35
+ def wait(wait_value = nil, timeout_value = @timeout_value)
36
+ call
37
+ return unless wait_value
38
+
39
+ Timeout.timeout(Integer(timeout_value)) do
40
+ until @log.read.match(wait_value)
41
+ sleep 0.01
42
+ end
43
+ end
44
+ rescue Timeout::Error
45
+ raise "Timeout waiting for #{@command.inspect} to find a match using #{ wait_value.inspect } in \n'#{ log.read }'"
46
+ false
47
+ end
48
+
49
+ def alive?
50
+ return false unless @pid
51
+ Process.kill(0, @pid)
52
+ rescue Errno::ESRCH, Errno::EPERM
53
+ false
54
+ end
55
+
56
+ def stop
57
+ return unless alive?
58
+ Process.kill('TERM', @pid)
59
+ Process.wait(@pid)
60
+ end
61
+
62
+ def check_alive!
63
+ raise "#{@original_command} has exited unexpectedly: #{@log.read}" unless alive?
64
+ end
65
+
66
+ private def call
67
+ @pid ||= Process.spawn(@command)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,36 @@
1
+ require 'tempfile'
2
+
3
+ class Rundoc::CodeCommand::Background
4
+ class Start < Rundoc::CodeCommand
5
+ def initialize(command, name: , wait: nil, timeout: 5, log: Tempfile.new("log"), out: "2>&1", allow_fail: false)
6
+ @command = command
7
+ @name = name
8
+ @wait = wait
9
+ @allow_fail = allow_fail
10
+
11
+ @spawn = ProcessSpawn.new(
12
+ @command,
13
+ timeout: timeout,
14
+ log: log,
15
+ out: out
16
+ )
17
+ ProcessSpawn.add(@name, @spawn)
18
+ end
19
+
20
+ def to_md(env = {})
21
+ return "$ #{@command}"
22
+ end
23
+
24
+ def call(env = {})
25
+ @spawn.wait(@wait)
26
+ @spawn.check_alive! unless @allow_fail
27
+ @spawn.log.read
28
+ end
29
+
30
+ def alive?
31
+ !!@spawn.alive?
32
+ end
33
+ end
34
+ end
35
+
36
+ Rundoc.register_code_command(:"background.start", Rundoc::CodeCommand::Background::Start)