yarr 0.0.1

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.
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