orb 0.0.4 → 0.0.5

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.
data/README.md CHANGED
@@ -12,6 +12,11 @@ the file and replacing the `ORB{}` call.
12
12
 
13
13
  [Watch the video](#) (Coming Soon).
14
14
 
15
+ # I just want to use it with Rspec. How?
16
+
17
+ Add `ORB{}` to a pending example, then run your spec suite with
18
+ `-r orb`, for example, `spec -rorb spec/**/*_spec.rb`, or add it to `spec_opts`.
19
+
15
20
  # Can I use this with \#{framework}?
16
21
 
17
22
  Probably. Have a look at `lib/orb/adapters/rspec.rb`. It's a pretty simple
data/lib/orb.rb CHANGED
@@ -1,30 +1,83 @@
1
+ # ORB is a tool to write tests interactively.
2
+
3
+ # Most ruby programmers, even the ones with extensive test suites, frequently
4
+ # find themselves in IRB, trying snippets of code here and there.
5
+ # It's not uncommon to run some code in IRB, then copy parts of it almost
6
+ # verbatim into a test file for use as a test. ORB makes this a much more smooth
7
+ # process.
8
+
9
+ # The basic workflow with ORB is:
10
+
11
+ # 1. Add `ORB{}` to each new test, at the point where you'd like to insert code.
12
+ # 2. Run your test suite with `orb` loaded. See `adapters/rspec.rb`.
13
+ # 3. Use the REPL provided for each call to ORB to create a new test.
14
+
15
+ # When a call to `ORB` is encountered, you'll be dropped to to a REPL with full
16
+ # access to the test's context (much like a debugger). You can run code, and
17
+ # interact with the context however you like. When you're ready to write your
18
+ # test, you simply run the commands, then add them to a buffer. Once your
19
+ # buffer contains the code you'd like to save as a test, you can write
20
+ # it back to the file in place of the call to `ORB` with just two keystrokes.
21
+
22
+ # The REPL uses readline for line editing.
1
23
  require 'readline'
24
+
25
+ # Adapters are near-trivial to write, and provide test-framework integration.
2
26
  require 'orb/adapters/rspec'
3
27
 
4
- module ORB
5
-
6
- def self.capture(bind)
7
- buf, line, last = [], "", ""
28
+ class ORB
29
+ @@index=0
30
+ def initialize(bind)
31
+ @@index += 1
32
+ @buf, @hist = [], []
33
+ @line, @file = bind.eval("[__LINE__, __FILE__]")
8
34
 
9
- puts ORB::Adapter.header(bind)
35
+ puts "\n\n[[ #{ORB::Adapter.header(bind)} ]]"
10
36
 
11
- while line = Readline.readline("ORB >> ", true)
12
-
37
+ while line = Readline.readline(prompt, true)
13
38
  case line
14
- when "a"
15
- buf << last
39
+
40
+ # The `a` command appends one or more recent lines to the test buffer.
41
+ when /^a\s?(\d*)$/
42
+ append_to_buffer($1.to_i)
16
43
  next
44
+
45
+ # The `h` command shows this session's history. Each line starts with
46
+ # a coloured space. A red space indicates that this line is not in
47
+ # the buffer, and a green space indicates that this line is in the
48
+ # buffer, and will be written back to the file when the test is saved.
49
+ when "h"
50
+ red = "\x1B[41m \x1B[m"
51
+ green = "\x1B[42m \x1B[m"
52
+ @hist.each do |line, in_buf|
53
+ print in_buf ? green : red
54
+ print ' '
55
+ puts line
56
+ end
57
+ next
58
+
59
+ # The `p` command prints the current contents of the buffer. If the test
60
+ # is written back to the file right now, this is what will be inserted.
17
61
  when "p"
18
- puts buf
62
+ puts @buf
19
63
  next
64
+
65
+ # The `q` command exits this session without writing a test. Next time
66
+ # the suite is run, you'll get a REPL here again.
20
67
  when "q"
21
- __orb_original_pending(message)
22
68
  break
69
+
70
+ # The `s` command writes the contents of the buffer out to the file.
23
71
  when "s"
24
- line, file = bind.eval("[__LINE__, __FILE__]")
25
- ORB.write_buf_to_file(buf, line, file)
72
+ write_buf_to_file
26
73
  break
74
+
75
+ # If this line wasn't a command, evaluate it in the context of the code
76
+ # that called `ORB{}`. We're stealing that context from the block.
77
+ # There are other, trickier tricks to get it without requiring a block,
78
+ # but they haven't been reliable since ruby 1.8.5.
27
79
  else
80
+ @hist << [line,false]
28
81
  begin
29
82
  this = bind.eval("self")
30
83
  ret = this.send(:eval, line, this.send(:binding))
@@ -35,26 +88,49 @@ module ORB
35
88
  end
36
89
  end
37
90
 
38
- last = line
39
91
  end
40
92
  end
41
93
 
42
- def self.write_buf_to_file(buf, line_num, file)
43
- lines = File.read(file).lines.to_a
94
+ private
95
+
96
+ # Append some number of recent lines to the test buffer. This is triggered
97
+ # by the command `a` or `a <n>`, eg. `a 3`. If called with no number, just
98
+ # appends the last command run, otherwise, appends n lines.
99
+ def append_to_buffer(n=1)
100
+ @hist.last[1] = true
101
+ @buf << @hist.last[0]
102
+ end
103
+
104
+ # When this command is run, ORB will save the contents of the test buffer
105
+ # back into the file where `ORB{}` was called from. It does this by reading
106
+ # in the entire file, then rewriting it with ORB{} replaced by the buffer.
107
+ def write_buf_to_file
108
+ lines = File.read(@file).lines.to_a
44
109
 
45
- File.open(file,"w") do |f|
46
- f.puts lines[0...line_num-1]
110
+ File.open(@file,"w") do |f|
111
+ f.puts lines[0...@line-1]
47
112
 
48
- orbline = lines[line_num-1]
113
+ orbline = lines[@line-1]
49
114
  indentation = orbline.index(/[^\s]/)
50
-
51
- buf.each do |bufline|
115
+
116
+ # Here we're indenting the inserted code to the same level as `ORB{}`
117
+ # was indented.
118
+ @buf.each do |bufline|
52
119
  f.print " "*indentation
53
120
  f.puts bufline
54
121
  end
55
122
 
56
- f.puts lines[line_num..-1]
123
+ f.puts lines[@line..-1]
57
124
  end
58
125
  end
59
126
 
127
+ # ORB's prompt looks like `1:0 >>`. The first number is the index of this
128
+ # test, starting at one, and incrementing with each test during an
129
+ # ORB-enhanced run of your test suite. The second number is the current size
130
+ # of the test buffer; that is, the number of lines that will be written to
131
+ # the file if the test is saved right now.
132
+ def prompt
133
+ "#{@@index}:#{@buf.size} >> "
134
+ end
135
+
60
136
  end
@@ -1,6 +1,15 @@
1
- require 'spec/example/pending'
1
+ ### ORB RSpec Adapter
2
+ # This integrates ORB with RSpec. To run your test suite with ORB enabled,
3
+ # run `spec` with `-rorb`, or add `-rorb` to `spec_opts`, or simply
4
+ # `require 'orb'` in your `spec_helper.rb`.
2
5
 
3
- module ORB
6
+ # ORB's requirements of an adapter are minimal:
7
+
8
+ # - (optional) Some convenient way to start an ORB session.
9
+ # - (optional) A header describing this specific instance.
10
+ # Each RSpec example has a description that's printed when it fails.
11
+ # We re-create that here to provide context when an ORB session is started.
12
+ class ORB
4
13
  module Adapters
5
14
  module RSpec
6
15
  def self.header(bind)
@@ -12,14 +21,20 @@ module ORB
12
21
  end
13
22
  end
14
23
 
24
+ # Initially, I wanted to override `pending` as the method to start ORB,
25
+ # but as it turns out, the Object hackery I need to do to make ORB work
26
+ # requires a block. Requiring that pending be called with a block seems like
27
+ # an odd design choice, so instead I've made the method ORB,
28
+ # called like `ORB{}`.
15
29
  module Spec
16
30
  module Example
17
31
  module Pending
18
32
  def ORB(&block)
19
- ORB.capture(block.binding)
33
+ ORB.new(block.binding)
20
34
  end
21
35
  end
22
36
  end
23
37
  end
24
38
 
39
+ # Finally, now that the RSpec Adapter is defined, set ORB's default Adapter.
25
40
  ORB::Adapter = ORB::Adapters::RSpec
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'orb'
3
- gem.version = "0.0.4"
3
+ gem.version = "0.0.5"
4
4
 
5
5
  gem.author, gem.email = 'Burke Libbey', "burke@burkelibbey.org"
6
6
 
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 4
9
- version: 0.0.4
8
+ - 5
9
+ version: 0.0.5
10
10
  platform: ruby
11
11
  authors:
12
12
  - Burke Libbey
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-01 00:00:00 -05:00
17
+ date: 2010-05-02 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -31,7 +31,6 @@ files:
31
31
  - README.md
32
32
  - orb.gemspec
33
33
  - lib/orb/adapters/rspec.rb
34
- - lib/orb/binding.rb
35
34
  - lib/orb.rb
36
35
  has_rdoc: true
37
36
  homepage:
@@ -1,32 +0,0 @@
1
- def Binding.of_caller(&block)
2
- old_critical, Thread.critical = Thread.critical, true
3
- count = 0
4
- cc = nil
5
- result, error = callcc{|c|cc=c;nil}
6
- error.call if error
7
-
8
- tracer = lambda do |*args|
9
- type, _, _, _, context = args
10
- if ["return", "c-return"].include?(type)
11
- count += 1
12
- # First this method and then calling one will return -- the trace event of the second event gets the context
13
- # of the method which called the method that called method.
14
- if count == 2
15
- set_trace_func(nil)
16
- cc.call(eval("binding", context), nil)
17
- end
18
- elsif type != "line"
19
- set_trace_func(nil)
20
- cc.call(nil, lambda { raise(Exception, "Binding.of_caller used in non-method context or trailing statements of method using it aren't in the block." ) })
21
- end
22
- end
23
-
24
- if result
25
- Thread.critical = old_critical
26
- yield result
27
- else
28
- set_trace_func(tracer)
29
- return nil
30
- end
31
- end
32
-