instant 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.
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: []