jsh 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -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
@@ -0,0 +1,8 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ desc "Run all specs."
4
+ RSpec::Core::RakeTask.new(:rspec) do |spec|
5
+ spec.pattern = 'spec/*_spec.rb'
6
+ spec.rspec_opts = %w(--format p --color)
7
+ end
8
+ task :default => :rspec
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)
@@ -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
@@ -0,0 +1,8 @@
1
+ require 'jsh/base'
2
+ require 'jsh/repl'
3
+
4
+ module JSH
5
+ def self.start(options = {})
6
+ REPL.start(options)
7
+ end
8
+ end
@@ -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
@@ -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) }
@@ -0,0 +1,10 @@
1
+ require 'v8'
2
+ require 'jsh/error_handler'
3
+
4
+ module JSH
5
+ class Context < V8::Context
6
+ def eval(*)
7
+ super rescue ErrorHandler.new($!)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module JSH
2
+ class ErrorHandler
3
+ def initialize(error)
4
+ @error = error
5
+ end
6
+
7
+ def to_s
8
+ @error.message
9
+ end
10
+ end
11
+ end
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module JSH
2
+ VERSION = '0.0.1'
3
+ end
@@ -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
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe JSH::Commands do
4
+ let(:commands){ JSH::Commands.new }
5
+ describe ".register" do
6
+ it "before key" do
7
+ JSH::Commands.register(:hey){ "hey" }
8
+ expect(commands.commands[:hey].call).to eq("hey")
9
+ end
10
+ end
11
+ end
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,2 @@
1
+ $:.unshift(File.expand_path("../../lib", __FILE__))
2
+ require 'jsh'
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: