jsh 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 +7 -0
- data/Gemfile +2 -0
- data/README.md +77 -0
- data/Rakefile +8 -0
- data/bin/jsh +16 -0
- data/jsh.gemspec +17 -0
- data/lib/jsh.rb +8 -0
- data/lib/jsh/base.rb +24 -0
- data/lib/jsh/commands.rb +20 -0
- data/lib/jsh/context.rb +10 -0
- data/lib/jsh/error_handler.rb +11 -0
- data/lib/jsh/hooks.rb +25 -0
- data/lib/jsh/pair.rb +27 -0
- data/lib/jsh/repl.rb +82 -0
- data/lib/jsh/version.rb +3 -0
- data/sample.rb +17 -0
- data/spec/commands_spec.rb +11 -0
- data/spec/hooks_spec.rb +18 -0
- data/spec/pair_spec.rb +23 -0
- data/spec/repl_spec.rb +49 -0
- data/spec/spec_helper.rb +2 -0
- metadata +98 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 23c0a2fde3b8781431b7c70fa0afc29b9cd750ca
|
4
|
+
data.tar.gz: 2d8c98f43f7b7a62ae0b7d6f66b9e04863763cc8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 639a4e8efa80029bed0429bf29c8ad0fa4d5da544f6be94e43294a8bb27663c85d4ab1dc2bc57fe9dd305079e9c6966afabb331a7336f80f42155bcbb633af23
|
7
|
+
data.tar.gz: b9d738b6b2cc74d8f536d11d1032b34af3db1494182609ffaba78d9c7451d5986b6e0860a4e07e93b64b72df86dc5664b885f8252a458a78563812a27644bbd2
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# JSH
|
2
|
+
|
3
|
+
This is an interactive shell for JavaScript which is written in Ruby.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
### Basic
|
8
|
+
|
9
|
+
```shell
|
10
|
+
$ jsh
|
11
|
+
[0] jsh) 1 + 1;
|
12
|
+
2
|
13
|
+
[1] jsh) "hello world".length;
|
14
|
+
11
|
15
|
+
[2] jsh) (function fib(n){ return (n < 2) ? 1 : fib(n - 2) + fib(n - 1); })(10);
|
16
|
+
89
|
17
|
+
```
|
18
|
+
|
19
|
+
### Customize
|
20
|
+
|
21
|
+
You can customize in these way.
|
22
|
+
Then save and execute it.
|
23
|
+
|
24
|
+
#### `hooks`
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require 'jsh'
|
28
|
+
|
29
|
+
JSH::Hooks.register(:before) do
|
30
|
+
puts "before hook!"
|
31
|
+
end
|
32
|
+
|
33
|
+
JSH::Hooks.register(:after) do
|
34
|
+
puts "after hook!"
|
35
|
+
end
|
36
|
+
|
37
|
+
JSH.start
|
38
|
+
```
|
39
|
+
|
40
|
+
#### `commands`
|
41
|
+
|
42
|
+
Save this file as `foo.rb`.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
require 'jsh'
|
46
|
+
|
47
|
+
JSH::Commands.register(:enable_to_say) do |jsh|
|
48
|
+
jsh.context['say'] = lambda{|this, word, times| word * times }
|
49
|
+
end
|
50
|
+
|
51
|
+
JSH.start
|
52
|
+
```
|
53
|
+
|
54
|
+
Then execute it.
|
55
|
+
|
56
|
+
```shell
|
57
|
+
$ ruby foo.rb
|
58
|
+
[0] jsh) enable_to_say
|
59
|
+
[1] jsh) say('Hello', 3)
|
60
|
+
HelloHelloHello
|
61
|
+
```
|
62
|
+
|
63
|
+
### Options
|
64
|
+
|
65
|
+
#### `-r --readline=BOOLEAN`
|
66
|
+
|
67
|
+
readline option should be boolean.
|
68
|
+
default value is `true`.
|
69
|
+
if set `false` to this option, jsh will not use Readline to input.
|
70
|
+
|
71
|
+
#### `--noprompt`
|
72
|
+
|
73
|
+
if use `--noprompt`, jsh will not print prompt.
|
74
|
+
|
75
|
+
## License
|
76
|
+
|
77
|
+
The MIT License
|
data/Rakefile
ADDED
data/bin/jsh
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path("../../lib", __FILE__))
|
4
|
+
|
5
|
+
require 'jsh'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
options, option_parser = {}, OptionParser.new
|
9
|
+
option_parser.version = JSH::VERSION
|
10
|
+
|
11
|
+
option_parser.on('-r', '--readline BOOLEAN', TrueClass){|v| p(v.class);options[:readline] = v }
|
12
|
+
option_parser.on('--noprompt'){|v| options[:noprompt] = v }
|
13
|
+
|
14
|
+
option_parser.parse!(ARGV)
|
15
|
+
|
16
|
+
JSH.start(options)
|
data/jsh.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path("../lib/jsh/version", __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new "jsh", JSH::VERSION do |s|
|
4
|
+
s.description = "Interactive shell for JavaScript which is written in Ruby."
|
5
|
+
s.summary = "Interactive shell for JavaScript"
|
6
|
+
s.author = "namusyaka"
|
7
|
+
s.email = "namusyaka@gmail.com"
|
8
|
+
s.homepage = "https://github.com/namusyaka/jsh"
|
9
|
+
s.files = `git ls-files`.split($/)
|
10
|
+
s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
11
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.license = "MIT"
|
14
|
+
|
15
|
+
s.add_dependency "therubyracer"
|
16
|
+
s.add_development_dependency "rspec"
|
17
|
+
end
|
data/lib/jsh.rb
ADDED
data/lib/jsh/base.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'jsh/context'
|
2
|
+
require 'jsh/commands'
|
3
|
+
require 'jsh/hooks'
|
4
|
+
require 'jsh/version'
|
5
|
+
|
6
|
+
module JSH
|
7
|
+
class Base
|
8
|
+
def context
|
9
|
+
@context ||= Context.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def output
|
13
|
+
STDOUT
|
14
|
+
end
|
15
|
+
|
16
|
+
def commands
|
17
|
+
@commands ||= Commands.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def hooks
|
21
|
+
@hooks ||= Hooks.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/jsh/commands.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'jsh/pair'
|
2
|
+
|
3
|
+
module JSH
|
4
|
+
class Commands < Pair
|
5
|
+
DEFAULT_COMMANDS = {}
|
6
|
+
|
7
|
+
alias commands data
|
8
|
+
|
9
|
+
def default_data
|
10
|
+
DEFAULT_COMMANDS
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.register(key, &block)
|
14
|
+
DEFAULT_COMMANDS[key] = block
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
exit_lambda = lambda { throw :halt }
|
20
|
+
%w[quit exit].each{|key| JSH::Commands.register(key.to_sym, &exit_lambda) }
|
data/lib/jsh/context.rb
ADDED
data/lib/jsh/hooks.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'jsh/pair'
|
2
|
+
|
3
|
+
module JSH
|
4
|
+
class Hooks < Pair
|
5
|
+
DEFAULT_HOOKS = {
|
6
|
+
:before => [],
|
7
|
+
:after => []
|
8
|
+
}
|
9
|
+
|
10
|
+
alias hooks data
|
11
|
+
|
12
|
+
def default_data
|
13
|
+
DEFAULT_HOOKS
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.register(key, &block)
|
17
|
+
(DEFAULT_HOOKS[key] ||= []) << block
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
JSH::Hooks.register(:before) do
|
23
|
+
puts "JSH ver #{JSH::VERSION}"
|
24
|
+
puts "If you want to stop, exec `exit` or `quit`"
|
25
|
+
end
|
data/lib/jsh/pair.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module JSH
|
2
|
+
class Pair
|
3
|
+
attr_accessor :data
|
4
|
+
|
5
|
+
def initialize(data = nil)
|
6
|
+
@data = data || default_data
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](key)
|
10
|
+
@data[key]
|
11
|
+
end
|
12
|
+
|
13
|
+
def []=(key, value)
|
14
|
+
@data[key] = value
|
15
|
+
end
|
16
|
+
|
17
|
+
def all
|
18
|
+
@data
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def default_data
|
24
|
+
{}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/jsh/repl.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'jsh/base'
|
2
|
+
require 'readline'
|
3
|
+
|
4
|
+
module JSH
|
5
|
+
class REPL
|
6
|
+
DEFAULT_PROMPT = "[{:number_of_times:}] jsh) "
|
7
|
+
PROMPT_SYNTAX = /\{:(.+?):\}/
|
8
|
+
|
9
|
+
attr_accessor :base, :prompt
|
10
|
+
|
11
|
+
def self.start(options)
|
12
|
+
new(Base.new, options).start
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(base, options = {})
|
16
|
+
@base = base
|
17
|
+
@noprompt = options.fetch(:noprompt, false)
|
18
|
+
@readline = options.fetch(:readline, true)
|
19
|
+
@options = options
|
20
|
+
config[:number_of_times] = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
call_hook(:before)
|
25
|
+
repl
|
26
|
+
call_hook(:after)
|
27
|
+
end
|
28
|
+
|
29
|
+
def repl
|
30
|
+
catch :halt do
|
31
|
+
loop do
|
32
|
+
input = read
|
33
|
+
if command = commands[input.to_sym]
|
34
|
+
command.arity != 0 ? command.call(base) : command.call
|
35
|
+
else
|
36
|
+
output.puts((input.nil? or input.empty?) ? "" : base.context.eval(input))
|
37
|
+
end
|
38
|
+
config[:number_of_times] += 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def noprompt?
|
44
|
+
@noprompt
|
45
|
+
end
|
46
|
+
|
47
|
+
def readline?
|
48
|
+
@readline
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def setup_prompt
|
54
|
+
(self.prompt ||= DEFAULT_PROMPT).gsub(PROMPT_SYNTAX){ config[$1.to_sym] || key }
|
55
|
+
end
|
56
|
+
|
57
|
+
def read
|
58
|
+
if readline?
|
59
|
+
Readline.readline(noprompt? ? "" : setup_prompt, true)
|
60
|
+
else
|
61
|
+
print setup_prompt unless noprompt?
|
62
|
+
gets.chomp
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def config
|
67
|
+
@config ||= {}
|
68
|
+
end
|
69
|
+
|
70
|
+
def output
|
71
|
+
@output ||= base.output
|
72
|
+
end
|
73
|
+
|
74
|
+
def commands
|
75
|
+
@commands ||= base.commands
|
76
|
+
end
|
77
|
+
|
78
|
+
def call_hook(key)
|
79
|
+
base.hooks[key].map(&:call)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/jsh/version.rb
ADDED
data/sample.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
$:.unshift(File.expand_path("../lib", __FILE__))
|
3
|
+
require 'jsh'
|
4
|
+
|
5
|
+
JSH::Hooks.register(:before) do
|
6
|
+
puts "before hook!"
|
7
|
+
end
|
8
|
+
|
9
|
+
JSH::Hooks.register(:after) do
|
10
|
+
puts "after hook!"
|
11
|
+
end
|
12
|
+
|
13
|
+
JSH::Commands.register(:enable_to_say) do |jsh|
|
14
|
+
jsh.context['say'] = lambda{|this, word, times| word * times }
|
15
|
+
end
|
16
|
+
|
17
|
+
JSH.start
|
data/spec/hooks_spec.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe JSH::Hooks do
|
4
|
+
let(:hooks){ JSH::Hooks.new }
|
5
|
+
describe ".register" do
|
6
|
+
context "for key that is pre-defined" do
|
7
|
+
it "before key" do
|
8
|
+
JSH::Hooks.register(:before){ "hello" }
|
9
|
+
expect(hooks.hooks[:before].last.call).to eq("hello")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "after key" do
|
13
|
+
JSH::Hooks.register(:after){ "hello" }
|
14
|
+
expect(hooks.hooks[:after].last.call).to eq("hello")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/spec/pair_spec.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe JSH::Pair do
|
4
|
+
let(:pair){ JSH::Pair.new }
|
5
|
+
|
6
|
+
describe "#[]" do
|
7
|
+
before { pair.data[:foo] = :bar }
|
8
|
+
subject { pair[:foo] }
|
9
|
+
it { should eq(:bar) }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#[]=" do
|
13
|
+
before { pair[:bar] = :foo }
|
14
|
+
it { expect(pair[:bar]).to eq(:foo) }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "all" do
|
18
|
+
let(:all){ 10.times{|n| pair["test_#{n}"] = n }}
|
19
|
+
before { pair.data = all }
|
20
|
+
subject { pair.data }
|
21
|
+
it { should eq(all) }
|
22
|
+
end
|
23
|
+
end
|
data/spec/repl_spec.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe JSH::REPL do
|
4
|
+
describe ".start" do
|
5
|
+
context "with readline option" do
|
6
|
+
it "should set true to @readline." do
|
7
|
+
repl = JSH::REPL.new(JSH::Base, :readline => true)
|
8
|
+
expect(repl.instance_variable_get(:@readline)).to be_true
|
9
|
+
expect(repl.readline?).to be_true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "without readline option" do
|
14
|
+
it "should set true as default value to @readline." do
|
15
|
+
repl = JSH::REPL.new(JSH::Base)
|
16
|
+
expect(repl.instance_variable_get(:@readline)).to be_true
|
17
|
+
expect(repl.readline?).to be_true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "with noprompt option" do
|
22
|
+
it "should set true to @noprompt." do
|
23
|
+
repl = JSH::REPL.new(JSH::Base, :noprompt => true)
|
24
|
+
expect(repl.instance_variable_get(:@noprompt)).to be_true
|
25
|
+
expect(repl.noprompt?).to be_true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "without noprompt option" do
|
30
|
+
it "should set false as default value to @noprompt." do
|
31
|
+
repl = JSH::REPL.new(JSH::Base)
|
32
|
+
expect(repl.instance_variable_get(:@noprompt)).to be_false
|
33
|
+
expect(repl.noprompt?).to be_false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#call_hook" do
|
39
|
+
let(:repl){ JSH::REPL.new(JSH::Base.new) }
|
40
|
+
let(:test){ [] }
|
41
|
+
before do
|
42
|
+
JSH::Hooks.register(:before){ test << :before }
|
43
|
+
JSH::Hooks.register(:after){ test << :after }
|
44
|
+
Readline.stub(:readline).and_return(:quit)
|
45
|
+
repl.start
|
46
|
+
end
|
47
|
+
it { expect(test).to eq([:before, :after]) }
|
48
|
+
end
|
49
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jsh
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- namusyaka
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: therubyracer
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Interactive shell for JavaScript which is written in Ruby.
|
42
|
+
email: namusyaka@gmail.com
|
43
|
+
executables:
|
44
|
+
- jsh
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- Gemfile
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- bin/jsh
|
52
|
+
- jsh.gemspec
|
53
|
+
- lib/jsh.rb
|
54
|
+
- lib/jsh/base.rb
|
55
|
+
- lib/jsh/commands.rb
|
56
|
+
- lib/jsh/context.rb
|
57
|
+
- lib/jsh/error_handler.rb
|
58
|
+
- lib/jsh/hooks.rb
|
59
|
+
- lib/jsh/pair.rb
|
60
|
+
- lib/jsh/repl.rb
|
61
|
+
- lib/jsh/version.rb
|
62
|
+
- sample.rb
|
63
|
+
- spec/commands_spec.rb
|
64
|
+
- spec/hooks_spec.rb
|
65
|
+
- spec/pair_spec.rb
|
66
|
+
- spec/repl_spec.rb
|
67
|
+
- spec/spec_helper.rb
|
68
|
+
homepage: https://github.com/namusyaka/jsh
|
69
|
+
licenses:
|
70
|
+
- MIT
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 2.0.2
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: Interactive shell for JavaScript
|
92
|
+
test_files:
|
93
|
+
- spec/commands_spec.rb
|
94
|
+
- spec/hooks_spec.rb
|
95
|
+
- spec/pair_spec.rb
|
96
|
+
- spec/repl_spec.rb
|
97
|
+
- spec/spec_helper.rb
|
98
|
+
has_rdoc:
|