orb 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in orb.gemspec
4
+ gemspec
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+ - MiniTest/RSpec support
2
+ - Writing back to files
3
+ - Readme
4
+ - Screencast
data/lib/orb.rb CHANGED
@@ -1,154 +1,4 @@
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.
23
- require 'readline'
24
-
25
- # Adapters are near-trivial to write, and provide test-framework integration.
26
- require 'orb/adapters/rspec'
27
-
28
- class ORB
29
- @@index=0
30
-
31
- # Once ORB is called, the user is presented with a minimal IRB-like REPL,
32
- # where they can evaluate arbitrary ruby code or execute a set of built-in
33
- # commands to build up a test and save it back to the test file.
34
- def orb_it_up
35
- while line = Readline.readline(prompt, true)
36
- case line
37
-
38
- # The `a` command appends one or more recent lines to the test buffer.
39
- when /^a\s?(\d*)$/
40
- append_to_buffer($1.to_i)
41
- next
42
-
43
- # The `h` command shows this session's history. Each line starts with
44
- # a coloured space. A red space indicates that this line is not in
45
- # the buffer, and a green space indicates that this line is in the
46
- # buffer, and will be written back to the file when the test is saved.
47
- when "h"
48
- red = "\x1B[41m \x1B[m"
49
- green = "\x1B[42m \x1B[m"
50
- @hist.each do |line, in_buf|
51
- print in_buf ? green : red
52
- print ' '
53
- puts line
54
- end
55
- next
56
-
57
- # The `p` command prints the current contents of the buffer. If the test
58
- # is written back to the file right now, this is what will be inserted.
59
- when "p"
60
- puts @buf
61
- next
62
-
63
- # The `q` command exits this session without writing a test. Next time
64
- # the suite is run, you'll get a REPL here again.
65
- when "q"
66
- break
67
-
68
- # The `s` command writes the contents of the buffer out to the file.
69
- when "s"
70
- write_buf_to_file
71
- break
72
-
73
- # If this line wasn't a command, evaluate it in the context of the code
74
- # that called `ORB{}`. We're stealing that context from the block.
75
- # There are other, trickier tricks to get it without requiring a block,
76
- # but they haven't been reliable since ruby 1.8.5.
77
- else
78
- @hist << [line,false]
79
- begin
80
- this = @binding.eval("self")
81
- ret = this.send(:eval, line, @binding)
82
- rescue => e
83
- puts e.message
84
- else
85
- puts ret.inspect
86
- end
87
- end
88
-
89
- end
90
- end
91
-
92
- # It's up to the adapters to figure out the context we need to evaluate code
93
- # in. Typically, they'll grab it from an empty block. Adapters call this
94
- # intializer with a `Binding`, and we set a few instance variables for the
95
- # REPL to use. Notably, `@line` and `@file` are the location of the call
96
- # to ORB, where we should insert our code when the test is written out.
97
- def initialize(bind)
98
- @@index += 1
99
- @binding = bind
100
- @buf, @hist = [], []
101
- @line, @file = bind.eval("[__LINE__, __FILE__]")
102
-
103
- # This is normally used for the test's description. It's not a strict
104
- # requirement of an adapter, but will be set and shown if present.
105
- @header = ORB::Adapter.header(bind) if ORB::Adapter.respond_to?(:header)
106
- puts "\n\n[[ #{@header} ]]" if @header
107
-
108
- # Gentlemen, start your REPLs.
109
- orb_it_up
110
- end
111
-
112
- private
113
-
114
- # Append some number of recent lines to the test buffer. This is triggered
115
- # by the command `a` or `a <n>`, eg. `a 3`. If called with no number, just
116
- # appends the last command run, otherwise, appends n lines.
117
- def append_to_buffer(n=1)
118
- @hist.last[1] = true
119
- @buf << @hist.last[0]
120
- end
121
-
122
- # When this command is run, ORB will save the contents of the test buffer
123
- # back into the file where `ORB{}` was called from. It does this by reading
124
- # in the entire file, then rewriting it with ORB{} replaced by the buffer.
125
- def write_buf_to_file
126
- lines = File.read(@file).lines.to_a
127
-
128
- File.open(@file,"w") do |f|
129
- f.puts lines[0...@line-1]
130
-
131
- orbline = lines[@line-1]
132
- indentation = orbline.index(/[^\s]/)
133
-
134
- # Here we're indenting the inserted code to the same level as `ORB{}`
135
- # was indented.
136
- @buf.each do |bufline|
137
- f.print " "*indentation
138
- f.puts bufline
139
- end
140
-
141
- f.puts lines[@line..-1]
142
- end
143
- end
144
-
145
- # ORB's prompt looks like `1:0 >>`. The first number is the index of this
146
- # test, starting at one, and incrementing with each test during an
147
- # ORB-enhanced run of your test suite. The second number is the current size
148
- # of the test buffer; that is, the number of lines that will be written to
149
- # the file if the test is saved right now.
150
- def prompt
151
- "#{@@index}:#{@buf.size} >> "
152
- end
153
-
154
- end
1
+ require 'orb/test_buffer'
2
+ require 'orb/pry_extensions'
3
+ require 'orb/drivers/test-unit'
4
+ require 'orb/runner'
@@ -0,0 +1,26 @@
1
+ require 'test/unit/testcase'
2
+
3
+ class Test::Unit::TestCase
4
+ def self.orb!
5
+ define_method("test_orb_#{rand 100000}") { orb!(self) }
6
+ end
7
+
8
+ def orb!(ctx)
9
+ with_immediate_asserts(ctx) { Orb::Runner.new(ctx).run }
10
+ end
11
+
12
+ def with_immediate_asserts(ctx)
13
+ class << self
14
+ alias_method :_original_wrap_assertion, :_wrap_assertion
15
+ def _wrap_assertion ; yield ; end
16
+ end
17
+
18
+ yield
19
+
20
+ class << self
21
+ alias_method :_wrap_assertion, :_original_wrap_assertion
22
+ end
23
+ end
24
+
25
+ end
26
+
@@ -0,0 +1,48 @@
1
+ require 'pry'
2
+
3
+ Pry.config.prompt = proc { |_, _, pry| "orb[#{pry.instance_variable_get("@orb_test_buffer")}]> " }
4
+
5
+ class Pry
6
+ attr_accessor :orb_test_buffer
7
+
8
+ module Helpers::CommandHelpers
9
+ def orb_test_buffer
10
+ _pry_.instance_variable_get("@orb_test_buffer")
11
+ end
12
+ end
13
+ end
14
+
15
+ module Orb
16
+ Commands = Pry::CommandSet.new do
17
+ command ",a", "Append the previous line to the buffer" do |*code|
18
+ if code.empty?
19
+ orb_test_buffer << _pry_.input_array[-1].chomp
20
+ else
21
+ orb_test_buffer << code.join(" ")
22
+ end
23
+ end
24
+
25
+ command ",p", "Print contents of buffer" do
26
+ puts orb_test_buffer
27
+ end
28
+
29
+ command ",e", "Edit contents of buffer" do
30
+ orb_test_buffer.edit_contents!
31
+ end
32
+
33
+ command ",n", "Name or rename the current test" do |*name|
34
+ orb_test_buffer.name = name.join(" ")
35
+ end
36
+
37
+ command ",r", "Run contents of buffer" do
38
+ orb_test_buffer.run
39
+ end
40
+
41
+ command ",w", "Write the buffer to file" do
42
+ orb_test_buffer.write
43
+ end
44
+ end
45
+ end
46
+
47
+ Pry.config.commands.import Orb::Commands
48
+
@@ -0,0 +1,35 @@
1
+ require 'pry'
2
+
3
+ module Orb
4
+ class Runner
5
+ attr_reader :test_buffer
6
+ class << self
7
+ attr_accessor :current
8
+ end
9
+
10
+ def initialize(context)
11
+ @context = context
12
+ @test_buffer = TestBuffer.new
13
+ setup_pry
14
+ Orb::Runner.current = self
15
+ end
16
+
17
+ def setup_pry
18
+ Pry.instance_eval do
19
+ if initial_session?
20
+ load_rc if Pry.config.should_load_rc
21
+ # load_plugins if Pry.config.plugins.enabled
22
+ load_requires if Pry.config.should_load_requires
23
+ load_history if Pry.config.history.should_load
24
+ end
25
+ end
26
+ @pry = Pry.new
27
+ @pry.instance_variable_set("@orb_test_buffer", @test_buffer)
28
+ end
29
+
30
+ def run
31
+ @pry.repl(@context)
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,39 @@
1
+ require 'tempfile'
2
+
3
+ class TestBuffer < Array
4
+ attr_accessor :name
5
+
6
+ def edit_contents!
7
+ path = "#{Dir::tmpdir}/orb-#{Kernel.rand 1000000}.rb"
8
+ begin
9
+ File.open(path, "w") do |f|
10
+ f.write(join('\n'))
11
+ f.flush
12
+ system("#{ENV['EDITOR'] || '/usr/bin/vim'} #{f.path}")
13
+ replace(File.read(f.path).lines.map(&:chomp))
14
+ end
15
+ ensure
16
+ File.unlink(path)
17
+ end
18
+ end
19
+
20
+ def run
21
+ each do |line|
22
+ eval(line)
23
+ end
24
+ end
25
+
26
+ def write
27
+ str = "".tap do |test|
28
+ test << "test \"#{name}\" do\n"
29
+ each do |line|
30
+ test << " " << line << "\n"
31
+ end
32
+ test << "end\n"
33
+ end
34
+
35
+ puts str
36
+ end
37
+
38
+ end
39
+
@@ -0,0 +1,3 @@
1
+ module Orb
2
+ VERSION = "0.1.0"
3
+ end
@@ -1,18 +1,21 @@
1
- Gem::Specification.new do |gem|
2
- gem.name = 'orb'
3
- gem.version = "0.0.6"
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "orb/version"
4
4
 
5
- gem.author, gem.email = 'Burke Libbey', "burke@burkelibbey.org"
5
+ Gem::Specification.new do |s|
6
+ s.name = "orb"
7
+ s.version = Orb::VERSION
8
+ s.authors = ["Burke Libbey"]
9
+ s.email = ["burke.libbey@shopify.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{REPL-driven testing for ruby}
12
+ s.description = %q{REPL-driven testing for ruby -- integrates with pry and lets you build tests incrementally in the REPL}
6
13
 
7
- gem.summary = "ORB is a tool to write tests interactively"
8
- gem.description = "ORB is a tool to write tests interactively. Add ORB{} to one of your tests, then when you run your test suite, you'll get dropped to a REPL, where you can explore the test's context and build an implementation for the test, before automatically writing it out to the file and replacing the ORB{} call."
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
9
18
 
10
- gem.has_rdoc = false
11
-
12
- gem.files = %w[
13
- LICENSE
14
- README.md
15
- lib
16
- orb.gemspec
17
- ] + Dir["**/*.rb"]
19
+ s.add_runtime_dependency 'pry', '0.9.8.2'
20
+ s.add_runtime_dependency 'test-unit'
18
21
  end
metadata CHANGED
@@ -1,66 +1,79 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: orb
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 6
9
- version: 0.0.6
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Burke Libbey
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2010-05-02 00:00:00 -05:00
18
- default_executable:
19
- dependencies: []
20
-
21
- description: ORB is a tool to write tests interactively. Add ORB{} to one of your tests, then when you run your test suite, you'll get dropped to a REPL, where you can explore the test's context and build an implementation for the test, before automatically writing it out to the file and replacing the ORB{} call.
22
- email: burke@burkelibbey.org
12
+ date: 2012-02-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: pry
16
+ requirement: &70298440802600 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - =
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.8.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70298440802600
25
+ - !ruby/object:Gem::Dependency
26
+ name: test-unit
27
+ requirement: &70298440801600 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70298440801600
36
+ description: REPL-driven testing for ruby -- integrates with pry and lets you build
37
+ tests incrementally in the REPL
38
+ email:
39
+ - burke.libbey@shopify.com
23
40
  executables: []
24
-
25
41
  extensions: []
26
-
27
42
  extra_rdoc_files: []
28
-
29
- files:
30
- - LICENSE
31
- - README.md
32
- - orb.gemspec
33
- - lib/orb/adapters/rspec.rb
43
+ files:
44
+ - .gitignore
45
+ - Gemfile
46
+ - Rakefile
47
+ - TODO
34
48
  - lib/orb.rb
35
- has_rdoc: true
36
- homepage:
49
+ - lib/orb/drivers/test-unit.rb
50
+ - lib/orb/pry_extensions.rb
51
+ - lib/orb/runner.rb
52
+ - lib/orb/test_buffer.rb
53
+ - lib/orb/version.rb
54
+ - orb.gemspec
55
+ homepage: ''
37
56
  licenses: []
38
-
39
57
  post_install_message:
40
58
  rdoc_options: []
41
-
42
- require_paths:
59
+ require_paths:
43
60
  - lib
44
- required_ruby_version: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - ">="
47
- - !ruby/object:Gem::Version
48
- segments:
49
- - 0
50
- version: "0"
51
- required_rubygems_version: !ruby/object:Gem::Requirement
52
- requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
55
- segments:
56
- - 0
57
- version: "0"
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
58
73
  requirements: []
59
-
60
74
  rubyforge_project:
61
- rubygems_version: 1.3.6
75
+ rubygems_version: 1.8.11
62
76
  signing_key:
63
77
  specification_version: 3
64
- summary: ORB is a tool to write tests interactively
78
+ summary: REPL-driven testing for ruby
65
79
  test_files: []
66
-
data/LICENSE DELETED
@@ -1,19 +0,0 @@
1
- Copyright (c) 2010 Burke Libbey <burke@burkelibbey.org>
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy
4
- of this software and associated documentation files (the "Software"), to deal
5
- in the Software without restriction, including without limitation the rights
6
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- copies of the Software, and to permit persons to whom the Software is
8
- furnished to do so, subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in
11
- all copies or substantial portions of the Software.
12
-
13
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- THE SOFTWARE.
data/README.md DELETED
@@ -1,33 +0,0 @@
1
- # ORB
2
-
3
- # What is it?
4
-
5
- ORB is a tool to write tests interactively. Add `ORB{}` to one of your
6
- tests, then when you run your test suite, you'll get dropped to a
7
- REPL, where you can explore the test's context and build an
8
- implementation for the test, before automatically writing it out to
9
- the file and replacing the `ORB{}` call.
10
-
11
- # Wait... What?
12
-
13
- [Watch the video](#) (Coming Soon).
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
-
20
- # Can I use this with \#{framework}?
21
-
22
- Probably. Have a look at `lib/orb/adapters/rspec.rb`. It's a pretty simple
23
- format.
24
-
25
- # Why do I have to call ORB with an empty block?
26
-
27
- Ruby 1.8.6 and onward doesn't have a reliable way to evaluate code in
28
- the context that calls a method without explicitly passing it, or
29
- grabbing the binding from a block. The block is easier to type.
30
-
31
- # I have a great idea...
32
-
33
- Great! Let me know, or even better, send me a pull request.
@@ -1,40 +0,0 @@
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`.
5
-
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
13
- module Adapters
14
- module RSpec
15
- def self.header(bind)
16
- this = bind.eval("self")
17
- ancestry = [this.class, this]
18
- ancestry.map(&:description).join(" ")
19
- end
20
- end
21
- end
22
- end
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{}`.
29
- module Spec
30
- module Example
31
- module Pending
32
- def ORB(&block)
33
- ORB.new(block.binding)
34
- end
35
- end
36
- end
37
- end
38
-
39
- # Finally, now that the RSpec Adapter is defined, set ORB's default Adapter.
40
- ORB::Adapter = ORB::Adapters::RSpec