orb 0.0.6 → 0.1.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.
@@ -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