instant 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ source :rubygems
2
+
3
+ gem "ruby2ruby", "~> 1.3.1"
4
+ gem "ruby_parser", "~> 2.3.1"
5
+
6
+ group :development do
7
+ gem "rspec", "~> 2.9.0"
8
+ gem "rake", "~> 1.1"
9
+ gem "echoe"
10
+ gem "autotest"
11
+ gem "pry"
12
+ end
13
+
14
+ group :production do
15
+ gem "sinatra", "~> 1.3.2"
16
+ gem "sinatra-synchrony", "~> 0.1.1"
17
+ gem "thin", "~> 1.3.1"
18
+ gem "foreman"
19
+ end
data/Manifest ADDED
@@ -0,0 +1,12 @@
1
+ Gemfile
2
+ Procfile
3
+ README.md
4
+ Rakefile
5
+ instant.gemspec
6
+ lib/instant.rb
7
+ lib/instant/context.rb
8
+ lib/instant/processor.rb
9
+ lib/instant/runner.rb
10
+ lib/instant/sinatra/app.rb
11
+ lib/instant/version.rb
12
+ Manifest
data/Procfile ADDED
@@ -0,0 +1 @@
1
+ server: bundle exec rackup -p $PORT
data/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # Instant
2
+
3
+ An experiment on real time visualize development tool, inspired by
4
+ [Bret Victor's Inventing on Principle](http://vimeo.com/36579366)
5
+ talk and [@ermau C# Implementation](https://github.com/ermau/Instant).
6
+
7
+ ## Install as gem
8
+
9
+ gem install instant
10
+
11
+ require 'instant'
12
+
13
+ runner = Instant::Runner.new
14
+ runner.run "def hello(a); a = 10 + a; end; hello(20)"
15
+
16
+ ## Run a demo
17
+
18
+ ![](http://f.cl.ly/items/0m2o252A3n1C032R2s0X/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202012-04-19%20%E4%B8%8A%E5%8D%8812.23.58.png)
19
+
20
+ You can run it live at [instant-ruby.herokuapp.com](http://instant-ruby.herokuapp.com).
21
+
22
+ ## Run locally
23
+
24
+ bundle install
25
+ foreman start
26
+
27
+ then open your browser at http://127.0.0.1:5000/
28
+
29
+ ## Credits
30
+
31
+ - [Bret Victor's Inventing on Principle](http://vimeo.com/36579366) - this talk is just eyes opening!
32
+ - [Instant (C#)](https://github.com/ermau/Instant) @ermau's C# implementation motivate me to create this Ruby port
33
+ - [ACE](http://ace.ajax.org/) - Really cool AJAX based IDE
34
+ - [RubyParser](https://github.com/seattlerb/ruby_parser) and [Ruby2Ruby](https://github.com/seattlerb/ruby2ruby) - created by Seattle.rb, they make this app possible
35
+
36
+ ## Contact
37
+
38
+ [@siuying](http://twitter.com/siuying)
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('instant', '0.0.1') do |p|
6
+ p.description = "Generate a unique token with Active Record."
7
+ p.url = "http://github.com/ryanb/uniquify"
8
+ p.author = "Ryan Bates"
9
+ p.email = "ryan@railscasts.com"
10
+ p.ignore_pattern = ["tmp/*", "script/*"]
11
+ p.development_dependencies = []
12
+ end
13
+
14
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
data/instant.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "instant"
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Ryan Bates"]
9
+ s.date = "2012-04-19"
10
+ s.description = "Generate a unique token with Active Record."
11
+ s.email = "ryan@railscasts.com"
12
+ s.extra_rdoc_files = ["README.md", "lib/instant.rb", "lib/instant/context.rb", "lib/instant/processor.rb", "lib/instant/runner.rb", "lib/instant/sinatra/app.rb", "lib/instant/version.rb"]
13
+ s.files = ["Gemfile", "Procfile", "README.md", "Rakefile", "instant.gemspec", "lib/instant.rb", "lib/instant/context.rb", "lib/instant/processor.rb", "lib/instant/runner.rb", "lib/instant/sinatra/app.rb", "lib/instant/version.rb", "Manifest"]
14
+ s.homepage = "http://github.com/ryanb/uniquify"
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Instant", "--main", "README.md"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = "instant"
18
+ s.rubygems_version = "1.8.15"
19
+ s.summary = "Generate a unique token with Active Record."
20
+
21
+ if s.respond_to? :specification_version then
22
+ s.specification_version = 3
23
+
24
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
+ else
26
+ end
27
+ else
28
+ end
29
+ end
data/lib/instant.rb ADDED
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+
3
+ require 'instant/processor'
4
+ require 'instant/context'
5
+ require 'instant/runner'
@@ -0,0 +1,93 @@
1
+ require 'logger'
2
+ require 'stringio'
3
+
4
+ module Instant
5
+ class LoopTooDeepError < StandardError; end
6
+
7
+ class LogCollector
8
+ def initialize(keys=[])
9
+ @logs = {}
10
+ keys.each {|k| @logs[k] = [] } if keys
11
+ end
12
+
13
+ def append(key, value)
14
+ @logs[key] ||= []
15
+
16
+ if @logs[key].length + 1 > 10
17
+ raise ::Instant::LoopTooDeepError.new("Loop too much")
18
+ end
19
+
20
+ @logs[key] << value
21
+ end
22
+
23
+ def fill_empty
24
+ max_length = @logs.values.collect{|v| v.length}.max
25
+ fill_keys = @logs.keys.select {|k| @logs[k].length < max_length }
26
+ fill_keys.each do |key|
27
+ @logs[key] << ""
28
+ end
29
+ end
30
+
31
+ def to_s
32
+ @logs.collect do |key, values|
33
+ value = values.collect {|v| v.to_s.center(5) }.join("|")
34
+ "#{key.to_s.ljust(8)} = #{value} "
35
+ end.join("\n")
36
+ end
37
+ end
38
+
39
+ class Context
40
+ def initialize
41
+ @stringio = StringIO.new
42
+ @assigns = Set.new
43
+ @loop_counter = 0
44
+ @logger = Logger.new(@stringio)
45
+ @logger.formatter = proc { |severity, datetime, progname, msg| "#{msg}\n" }
46
+
47
+ @log_collectors = []
48
+ @loop_counter = 0
49
+ end
50
+
51
+ def log_assign(name, value)
52
+ if @log_collectors.size > 0
53
+ @log_collectors.last.append name, value
54
+ else
55
+ @assigns << name
56
+ @logger.info "#{name.to_s.ljust(8)} = #{value.to_s.center(5)}"
57
+ end
58
+ return value
59
+ end
60
+
61
+ def loop_begin
62
+ @log_collectors.push LogCollector.new(@assigns)
63
+ end
64
+
65
+ def loop_inside_begin
66
+ end
67
+
68
+ def loop_inside_end
69
+ @log_collectors.last.fill_empty
70
+ @loop_counter = @loop_counter + 1
71
+
72
+ if @loop_counter > 1000
73
+ raise ::Instant::LoopTooDeepError.new("Loop too much")
74
+ end
75
+ end
76
+
77
+ def loop_end
78
+ collector = @log_collectors.pop
79
+ @logger.info collector.to_s
80
+ end
81
+
82
+ def close
83
+ while collector = @log_collectors.pop
84
+ @logger.info collector.to_s
85
+ end
86
+ end
87
+
88
+ def to_s
89
+ @stringio.string
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,63 @@
1
+ require 'ruby_parser'
2
+ require 'ruby2ruby'
3
+
4
+ module Instant
5
+ class Processor
6
+ def initialize
7
+ @parser = RubyParser.new
8
+ @generator = Ruby2Ruby.new
9
+ end
10
+
11
+ def process(source)
12
+ sexp = @parser.process(source)
13
+ sexp = process_sexp(sexp)
14
+ @generator.process(sexp)
15
+ end
16
+
17
+ private
18
+ def process_sexp(sexp)
19
+ sexp.inject(s()) do |s, node|
20
+ case node
21
+ when Sexp
22
+ name = node[0]
23
+ case name
24
+ when :lasgn
25
+ s << log_lasgn(node)
26
+ when :while
27
+ s << s(:call, nil, :loop_begin, s(:arglist))
28
+ s << log_while(node)
29
+ s << s(:call, nil, :loop_end, s(:arglist))
30
+ else
31
+ s << process_sexp(node)
32
+ end
33
+ else
34
+ s << node
35
+ end
36
+ s
37
+ end
38
+ end
39
+
40
+ # watch for :lasgn
41
+ def log_lasgn(node)
42
+ name = node[1]
43
+ expr = node[2]
44
+ s(:lasgn,
45
+ name,
46
+ s(:call, nil, :log_assign, s(:arglist, s(:lit, name), process_sexp(expr))))
47
+ end
48
+
49
+ # watch for :while
50
+ def log_while(node)
51
+ s(:while,
52
+ process_sexp(node[1]),
53
+ s(:block,
54
+ s(:call, nil, :loop_inside_begin, s(:arglist)),
55
+ process_sexp(node[2]),
56
+ s(:call, nil, :loop_inside_end, s(:arglist))),
57
+ true)
58
+ end
59
+
60
+ # watch for :masgn
61
+
62
+ end
63
+ end
@@ -0,0 +1,36 @@
1
+ require 'json'
2
+
3
+ module Instant
4
+ class Runner
5
+ def initialize(processor = Processor.new)
6
+ @processor = processor
7
+ end
8
+
9
+ def run(source)
10
+ begin
11
+ @processed = @processor.process(source)
12
+ context = Context.new
13
+
14
+ begin
15
+ return_value = context.instance_eval(@processed)
16
+ ensure
17
+ context.close
18
+ end
19
+ {:status => :ok, :result => context.to_s, :return_value => return_value}
20
+ rescue SyntaxError => e
21
+ {:status => :error, :cause => :syntax_error, :message => format_error(e), :result => context.to_s }
22
+ rescue Racc::ParseError => e
23
+ {:status => :error, :cause => :parse_error, :message => format_error(e), :result => context.to_s }
24
+ rescue Instant::LoopTooDeepError => e
25
+ {:status => :error, :cause => :loop_too_deep, :message => "Loop too deep", :result => context.to_s }
26
+ rescue StandardError => e
27
+ {:status => :error, :cause => :unknown, :message => format_error(e), :result => context.to_s }
28
+ end
29
+ end
30
+
31
+ private
32
+ def format_error(e)
33
+ "#{e.message}<br><br>#{ e.backtrace[0..10].join('<br>')}"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,30 @@
1
+ require 'json'
2
+ require 'sinatra/synchrony'
3
+
4
+ module Instant
5
+ module Sinatra
6
+ class App < ::Sinatra::Base
7
+ register ::Sinatra::Synchrony
8
+
9
+ set :public_folder, File.expand_path(File.join(File.dirname(__FILE__), "../../../public"))
10
+ set :views, File.expand_path(File.join(File.dirname(__FILE__), "../../../views"))
11
+
12
+ get '/' do
13
+ erb :index
14
+ end
15
+
16
+ post '/compile' do
17
+ content_type :json
18
+ source = params[:source]
19
+
20
+ puts "source:" + source
21
+ if source && source.strip != ""
22
+ result = Instant::Runner.new.run(source.strip)
23
+ result.to_json
24
+ else
25
+ {:status => :ok, :result => ""}.to_json
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module Instant
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: instant
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ryan Bates
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-19 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Generate a unique token with Active Record.
15
+ email: ryan@railscasts.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files:
19
+ - README.md
20
+ - lib/instant.rb
21
+ - lib/instant/context.rb
22
+ - lib/instant/processor.rb
23
+ - lib/instant/runner.rb
24
+ - lib/instant/sinatra/app.rb
25
+ - lib/instant/version.rb
26
+ files:
27
+ - Gemfile
28
+ - Procfile
29
+ - README.md
30
+ - Rakefile
31
+ - instant.gemspec
32
+ - lib/instant.rb
33
+ - lib/instant/context.rb
34
+ - lib/instant/processor.rb
35
+ - lib/instant/runner.rb
36
+ - lib/instant/sinatra/app.rb
37
+ - lib/instant/version.rb
38
+ - Manifest
39
+ homepage: http://github.com/ryanb/uniquify
40
+ licenses: []
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --line-numbers
44
+ - --inline-source
45
+ - --title
46
+ - Instant
47
+ - --main
48
+ - README.md
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '1.2'
63
+ requirements: []
64
+ rubyforge_project: instant
65
+ rubygems_version: 1.8.15
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Generate a unique token with Active Record.
69
+ test_files: []