yarr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5657e3c5f0e9c629f627e6c37f10e6e0ff334ccc
4
+ data.tar.gz: 887dd52989ca44d9f747f1548324e85e08b16c3e
5
+ SHA512:
6
+ metadata.gz: 34d485e0a8bc83d9b36aba6d9f536baf611c28bc354ca515bc8ef7e2f37e174aa939383ca57e984fb30ce88383278784f44352186e9e75cbf0e7f119cbe6b43b
7
+ data.tar.gz: fac01dd98db4aafa1891aff063490e9a13e21a0a5c6175582538bc5fe001b8a62a4bf62e580d9f580228b18786a8cf83a4916546c9415f3b8ea6e0f6adc44b77
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) Arturo Herrero, http://arturoherrero.com/
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,185 @@
1
+ # YARR
2
+
3
+ [![Code Climate](https://codeclimate.com/github/arturoherrero/yarr/badges/gpa.svg)](https://codeclimate.com/github/arturoherrero/yarr)
4
+ [![Build Status](https://travis-ci.org/arturoherrero/yarr.svg)](https://travis-ci.org/arturoherrero/yarr)
5
+
6
+ **YARR (Yet Another Ruby REPL)** is a Ruby REPL (just a hobby, won't be big and
7
+ professional like [Pry][1]). YARR was inspired by groovysh, IRB, Pry, Bash and Vim.
8
+
9
+ ## Installation
10
+
11
+ Install the gem:
12
+
13
+ ```
14
+ $ gem install yarr
15
+ ```
16
+
17
+ ## Features
18
+
19
+ An interactive shell for evaluating Ruby code from the command-line. YARR is a
20
+ command-line application which allows easy access to evaluate Ruby expressions,
21
+ define classes and run simple experiments. It also features command history.
22
+
23
+ ![yarr](yarr.png)
24
+
25
+ ### Evaluating Expressions
26
+
27
+ #### Simple Expressions
28
+
29
+ ```
30
+ ruby:001> puts "Hello"
31
+ Hello
32
+ ===> nil
33
+ ruby:002> [1,2,3].max
34
+ ===> 3
35
+ ```
36
+
37
+ #### Multi-line Expressions
38
+
39
+ Multi-line/complex expressions (like closure or class definitions) may be
40
+ defined over several lines. When the shell detects that it has a complete
41
+ expression it will evaluate it.
42
+
43
+ ```
44
+ ruby:001> class Foo
45
+ ruby:001* def bar
46
+ ruby:001* lambda do
47
+ ruby:001* 1
48
+ ruby:001* end
49
+ ruby:001* end
50
+ ruby:001* end
51
+ ===> :bar
52
+ ruby:002> Foo.new.bar.call
53
+ ===> 1
54
+ ```
55
+
56
+ #### Variables
57
+
58
+ Set a shell variable for later use.
59
+
60
+ ```
61
+ ruby:001> foo = "bar"
62
+ ===> bar
63
+ ```
64
+
65
+ #### Functions
66
+
67
+ Functions can be defined in the shell, and will be saved for later use.
68
+
69
+ Defining a function is easy:
70
+
71
+ ```
72
+ ruby:001> def hello(name)
73
+ ruby:001* puts "Hello #{name}"
74
+ ruby:001* end
75
+ ===> :hello
76
+ ```
77
+
78
+ And then using it is as one might expect:
79
+
80
+ ```
81
+ ruby:002> hello("Arturo")
82
+ Hello Arturo
83
+ ===> nil
84
+ ```
85
+
86
+ Variables and functions share the same namespace, be careful:
87
+
88
+ ```
89
+ ruby:001> foo = 10
90
+ ===> 10
91
+ ruby:002> def foo
92
+ ruby:002* 5
93
+ ruby:002* end
94
+ ===> :foo
95
+ ruby:003> foo
96
+ ===> 10
97
+ ```
98
+
99
+ ### Commands
100
+
101
+ The shell has a number of different commands, which provide access to the shell’s
102
+ environment.
103
+
104
+ #### `:exit` or `:quit`
105
+
106
+ Exit the shell.
107
+
108
+ This is the **only** way to exit the shell. No `Ctrl-c`, sorry.
109
+
110
+ ```
111
+ ruby:001> :exit
112
+ ```
113
+
114
+ #### `:help`
115
+
116
+ Display the list of commands (and aliases).
117
+
118
+ ```
119
+ ruby:001> :help
120
+
121
+ Available commands:
122
+ :exit Exit the shell
123
+ :help Display this help message
124
+ :hist Display edit-line history
125
+ :quit Alias to :exit
126
+ :number Execute a specific expression from history
127
+ :! cmd Execute a shell command à la Vim
128
+
129
+ ```
130
+
131
+ #### `:hist`
132
+
133
+ Display the shell history.
134
+
135
+ ```
136
+ ruby:001> def foo
137
+ ruby:001* "bar"
138
+ ruby:001* end
139
+ ===> :foo
140
+ ruby:002> var = 10
141
+ ===> 10
142
+ ruby:003> :! echo "Yay"
143
+ Yay
144
+ ruby:004> :hist
145
+ 001 def foo
146
+ "bar"
147
+ end
148
+ 002 var = 10
149
+ 003 :! echo "Yay"
150
+ 004 :hist
151
+ ```
152
+
153
+ #### `:number`
154
+
155
+ Execute a specific expression from history, e.g. `:1` or `:001`.
156
+
157
+ ```
158
+ ruby:001> var = 10
159
+ ===> 10
160
+ ruby:002> var = 5
161
+ ===> 5
162
+ ruby:003> var = 8
163
+ ===> 8
164
+ ruby:004> :2
165
+ ===> 5
166
+ ```
167
+
168
+ #### `:! cmd`
169
+
170
+ Execute a shell command à la Vim.
171
+
172
+ ```
173
+ ruby:001> :! cal
174
+ February 2015
175
+ Su Mo Tu We Th Fr Sa
176
+ 1 2 3 4 5 6 7
177
+ 8 9 10 11 12 13 14
178
+ 15 16 17 18 19 20 21
179
+ 22 23 24 25 26 27 28
180
+
181
+
182
+ ```
183
+
184
+
185
+ [1]: http://pryrepl.org/
data/bin/yarr ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path("../../lib/yarr", __FILE__)
4
+
5
+ YARR.new.call
data/lib/formatter.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Formatter
2
+ def bold(text)
3
+ "\033[1m#{text}\e[0m"
4
+ end
5
+
6
+ def red(text)
7
+ "\e[1;31m#{text}\e[0m"
8
+ end
9
+ end
@@ -0,0 +1,111 @@
1
+ require "readline"
2
+ require "stringio"
3
+ require_relative "formatter"
4
+
5
+ class Interpreter
6
+ include Formatter
7
+
8
+ def initialize
9
+ Readline.completion_append_character = nil
10
+ Readline.completion_proc = lambda do |input|
11
+ commands.grep(/^#{Regexp.escape(input)}/)
12
+ end
13
+ end
14
+
15
+ def call
16
+ separator = ">"
17
+ expression = ""
18
+ begin
19
+ expression += Readline.readline(prompt(separator), false)
20
+ Readline::HISTORY << expression
21
+ capture_stdout { eval(expression, TOPLEVEL_BINDING) }
22
+ rescue SyntaxError => e
23
+ if e.message =~ /syntax error, unexpected end-of-input/
24
+ Readline::HISTORY.pop
25
+ expression += "\n "
26
+ separator = "*"
27
+ retry
28
+ end
29
+ rescue Exception => e
30
+ end
31
+ process(expression)
32
+ end
33
+
34
+ private
35
+
36
+ def prompt(separator)
37
+ "#{bold("ruby")}:#{"%03d" % (Readline::HISTORY.size + 1)}#{bold(separator)} "
38
+ end
39
+
40
+ def process(expression)
41
+ if expression.chr == ":"
42
+ command(expression)
43
+ else
44
+ evaluate(expression)
45
+ end
46
+ end
47
+
48
+ def command(expression)
49
+ command, arguments = expression.split(" ", 2)
50
+ self.send(command[1..-1], arguments)
51
+ rescue
52
+ "#{red("ERROR")} #{command} command is not available"
53
+ end
54
+
55
+ def exit(args)
56
+ exit!
57
+ end
58
+ alias_method :quit, :exit
59
+
60
+ def help(args)
61
+ <<-END.gsub(/^\s+\|/, '')
62
+ |
63
+ |Available commands:
64
+ | #{bold(":exit")} Exit the shell
65
+ | #{bold(":help")} Display this help message
66
+ | #{bold(":hist")} Display edit-line history
67
+ | #{bold(":quit")} Alias to #{bold(":exit")}
68
+ | #{bold(":")}number Execute a specific expression from history
69
+ | #{bold(":!")} cmd Execute a shell command à la Vim
70
+ |
71
+ END
72
+ end
73
+
74
+ def hist(args)
75
+ "".tap do |history|
76
+ Readline::HISTORY.to_a.each.with_index(1) do |command, index|
77
+ history << " #{bold("%03d" % index)} #{command}\n"
78
+ end
79
+ end
80
+ end
81
+
82
+ define_method("!") do |args|
83
+ `#{args}`
84
+ end
85
+
86
+ def method_missing(name, *args)
87
+ index = (name.to_s[1..-1].to_i - 1).tap { |index| raise StandardError if index == -1 }
88
+ expression = Readline::HISTORY[index]
89
+ Readline::HISTORY.pop
90
+ Readline::HISTORY << expression
91
+ process(expression)
92
+ end
93
+
94
+ def evaluate(expression)
95
+ "#{bold("===>")} #{eval(expression, TOPLEVEL_BINDING)}"
96
+ rescue Exception => e
97
+ "#{red("ERROR")} #{e.message}"
98
+ end
99
+
100
+ def commands
101
+ %w(:exit :help :hist :quit :!)
102
+ end
103
+
104
+ def capture_stdout(&block)
105
+ stdout = $stdout
106
+ $stdout = StringIO.new
107
+ block.call
108
+ ensure
109
+ $stdout = stdout
110
+ end
111
+ end
data/lib/yarr.rb ADDED
@@ -0,0 +1,41 @@
1
+ require "io/console"
2
+ require_relative "formatter"
3
+ require_relative "interpreter"
4
+
5
+ class YARR
6
+ include Formatter
7
+
8
+ def initialize(args = {})
9
+ $stdout.sync = true
10
+ @interpreter = args.fetch(:interpreter) { Interpreter.new }
11
+ end
12
+
13
+ def call
14
+ banner
15
+ loop do
16
+ puts interpreter.call
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :interpreter
23
+
24
+ def banner
25
+ puts bold("YARR | Ruby #{RUBY_VERSION}")
26
+ puts "Type '#{bold(":help")}' for help."
27
+ puts bold("-" * IO.console.winsize.last)
28
+ end
29
+ end
30
+
31
+ class NilClass
32
+ def to_s
33
+ "nil"
34
+ end
35
+ end
36
+
37
+ class Symbol
38
+ def to_s
39
+ ":#{id2name}"
40
+ end
41
+ end
@@ -0,0 +1,114 @@
1
+ require "interpreter"
2
+
3
+ RSpec.describe Interpreter do
4
+ subject(:interpreter) { described_class.new }
5
+
6
+ it "executes simple expression" do
7
+ given("1")
8
+ expect(interpreter.call).to eq("\e[1m===>\e[0m 1")
9
+ end
10
+
11
+ it "executes one line expression" do
12
+ given("1 + 1")
13
+ expect(interpreter.call).to eq("\e[1m===>\e[0m 2")
14
+ end
15
+
16
+ it "executes multiline line declaration" do
17
+ result = RUBY_VERSION[0..2] >= "2.1" ? "foo" : ""
18
+ given("def foo", "1", "end")
19
+ expect(interpreter.call).to eq("\e[1m===>\e[0m #{result}")
20
+ end
21
+
22
+ it "executes multiline line declaration and invocation" do
23
+ setup("def foo", "1", "end")
24
+ given("foo")
25
+ expect(interpreter.call).to eq("\e[1m===>\e[0m 1")
26
+ end
27
+
28
+ describe ":hist" do
29
+ it "shows the history" do
30
+ setup("5")
31
+ setup("def foo", "1", "end")
32
+ setup("foo")
33
+ given(":hist")
34
+ expect(interpreter.call).to eq(<<-END.gsub(/^\s+\||$/, '')
35
+ | \e[1m001\e[0m 5
36
+ | \e[1m002\e[0m def foo
37
+ | 1
38
+ | end
39
+ | \e[1m003\e[0m foo
40
+ | \e[1m004\e[0m :hist
41
+ END
42
+ )
43
+ end
44
+ end
45
+
46
+ describe ":number" do
47
+ it "executes an expression from history" do
48
+ setup("var = 5")
49
+ setup("var = 0")
50
+ given(":001")
51
+ expect(interpreter.call).to eq("\e[1m===>\e[0m 5")
52
+ end
53
+
54
+ it "adds the command to the history" do
55
+ setup("var = 5")
56
+ setup("var = 0")
57
+ setup(":001")
58
+ given(":hist")
59
+ expect(interpreter.call).to eq(<<-END.gsub(/^\s+\||$/, '')
60
+ | \e[1m001\e[0m var = 5
61
+ | \e[1m002\e[0m var = 0
62
+ | \e[1m003\e[0m var = 5
63
+ | \e[1m004\e[0m :hist
64
+ END
65
+ )
66
+ end
67
+ end
68
+
69
+ describe ":! cmd" do
70
+ let(:output) { "-rw-r--r-- 1 arturo staff 39 16 Feb 21:11 spec.rb" }
71
+ before do
72
+ allow(interpreter).to receive(:'`').with("ls -l").and_return(output)
73
+ end
74
+
75
+ it "executes an external shell command" do
76
+ given(":! ls -l")
77
+ expect(interpreter.call).to eq(output)
78
+ end
79
+ end
80
+
81
+ context "invalid expression" do
82
+ it "returns a syntax error" do
83
+ given("1 + &")
84
+ expect(interpreter.call).to eq(<<-END.gsub(/^\s+\||\n$/, '')
85
+ |\e[1;31mERROR\e[0m <main>: syntax error, unexpected &
86
+ |1 + &
87
+ | ^
88
+ END
89
+ )
90
+ end
91
+ end
92
+
93
+ context "invalid command" do
94
+ it "returns a command error" do
95
+ given(":invalid")
96
+ expect(interpreter.call).to eq("\e[1;31mERROR\e[0m :invalid command is not available")
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def setup(*input)
103
+ given(*input)
104
+ interpreter.call
105
+ end
106
+
107
+ def given(*input)
108
+ allow(Readline).to receive(:readline).and_return(*input)
109
+ end
110
+
111
+ after(:each) do
112
+ Readline::HISTORY.clear
113
+ end
114
+ end
@@ -0,0 +1,18 @@
1
+ RSpec.configure do |config|
2
+ config.expect_with :rspec do |expectations|
3
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
4
+ end
5
+
6
+ config.mock_with :rspec do |mocks|
7
+ mocks.verify_partial_doubles = true
8
+ end
9
+
10
+ config.disable_monkey_patching!
11
+
12
+ if config.files_to_run.one?
13
+ config.default_formatter = 'doc'
14
+ end
15
+
16
+ config.order = :random
17
+ Kernel.srand config.seed
18
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yarr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Arturo Herrero
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: guard-rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.2'
55
+ description: YARR. Yet Another Ruby REPL. A Ruby REPL (just a hobby, won't be big
56
+ and professional like pry)
57
+ email: arturo.herrero@gmail.com
58
+ executables:
59
+ - yarr
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - LICENSE
64
+ - README.md
65
+ - bin/yarr
66
+ - lib/formatter.rb
67
+ - lib/interpreter.rb
68
+ - lib/yarr.rb
69
+ - spec/lib/interpreter_spec.rb
70
+ - spec/spec_helper.rb
71
+ homepage: https://github.com/arturoherrero/yarr
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 2.0.0
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 2.4.5
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: YARR. Yet Another Ruby REPL
95
+ test_files:
96
+ - spec/lib/interpreter_spec.rb
97
+ - spec/spec_helper.rb