rubish 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/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ begin
5
+ require 'rcov/rcovtask'
6
+
7
+ Rcov::RcovTask.new do |t|
8
+ t.libs << 'test'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ t.rcov_opts = ["-T -x '/Library/Ruby/*'"]
11
+ t.verbose = true
12
+ end
13
+ rescue LoadError
14
+ puts "Rcov not available. Install it for rcov-related tasks with: sudo gem install rcov"
15
+ end
16
+
17
+ begin
18
+ require 'jeweler'
19
+ Jeweler::Tasks.new do |s|
20
+ s.name = "rubish"
21
+ s.description = "Ruby Interactive Shell"
22
+ s.summary = s.description
23
+ s.email = "hayeah@gmail.com"
24
+ s.homepage = "http://github.com/hayeah/rubish"
25
+ s.authors = ["Howard Yeh"]
26
+ s.has_rdoc = true
27
+ s.extra_rdoc_files = ["LICENSE"]
28
+ s.files = FileList["[A-Z]*", "{bin,lib,test}/**/*"]
29
+ end
30
+
31
+ rescue LoadError
32
+ puts "Jeweler not available. Install it for jeweler-related tasks with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
33
+ end
34
+
35
+ Rake::TestTask.new do |t|
36
+ t.libs << 'lib'
37
+ t.pattern = 'test/**/*_test.rb'
38
+ t.verbose = false
39
+ end
40
+
41
+ Rake::RDocTask.new do |rdoc|
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = 'test'
44
+ rdoc.options << '--line-numbers' << '--inline-source'
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
48
+
49
+ desc "Build and install gem"
50
+ task :gem_install =>["gemspec", "build", "install"]
51
+
52
+ task :default => :test
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 0
3
+ :patch: 1
4
+ :major: 0
data/bin/rubish ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + '/../lib/rubish'
4
+
5
+ Rubish.repl
data/lib/rubish.rb ADDED
@@ -0,0 +1,24 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'pp'
5
+ require 'fileutils'
6
+ require 'readline'
7
+ require 'irb/input-method'
8
+ require 'irb/ruby-lex'
9
+
10
+ require 'rubish/stub'
11
+ require 'rubish/job'
12
+ require 'rubish/job_control'
13
+ require 'rubish/context'
14
+ require 'rubish/repl'
15
+ require 'rubish/workspace'
16
+ require 'rubish/executable'
17
+ require 'rubish/unix_executable'
18
+ require 'rubish/batch_executable'
19
+ require 'rubish/command'
20
+ require 'rubish/command_builder'
21
+ require 'rubish/pipe'
22
+ require 'rubish/streamer'
23
+ require 'rubish/sed'
24
+ require 'rubish/awk'
data/lib/rubish/awk.rb ADDED
@@ -0,0 +1,54 @@
1
+ class Rubish::Awk < Rubish::Streamer
2
+
3
+ attr_reader :a # array of fields
4
+ attr_reader :r # string of current record
5
+ attr_reader :nf # number of fields for current record
6
+
7
+ def initialize(exe)
8
+ super(exe)
9
+ @fs = /\s+/
10
+ @nf = 0 # number of fields for a record
11
+ @acts = []
12
+ @beg_act = nil
13
+ @end_act = nil
14
+ end
15
+
16
+ def rs=(*args)
17
+ raise "record separator not supported"
18
+ self
19
+ end
20
+
21
+ def fs(fs)
22
+ @fs = fs
23
+ self
24
+ end
25
+
26
+ def nr
27
+ lineno
28
+ end
29
+
30
+ def stream_begin
31
+ self.instance_eval(&@beg_act) if @beg_act
32
+ end
33
+
34
+ def init_line
35
+ @a = line.split(@fs)
36
+ @nf = @a.length
37
+ @r = line
38
+ end
39
+
40
+ def stream_end
41
+ self.instance_eval(&@end_act) if @end_act
42
+ end
43
+
44
+ def begin(&block)
45
+ @beg_act = block
46
+ self
47
+ end
48
+
49
+ def end(&block)
50
+ @end_act = block
51
+ self
52
+ end
53
+
54
+ end
@@ -0,0 +1,27 @@
1
+ # wraps all the processing in a context with a job
2
+ # (which encapsulates a thread).
3
+ class Rubish::BatchExecutable < Rubish::Executable
4
+
5
+
6
+ def initialize(context,&block)
7
+ @context = context
8
+ @proc = block
9
+ end
10
+
11
+ def exec!
12
+ ctxt = @context.derive(nil,self.i,self.o,self.err)
13
+ # this block will execute in a thread
14
+ Rubish::Job::ThreadJob.new {
15
+ begin
16
+ ctxt.eval &@proc
17
+ ensure
18
+ ctxt.job_control.waitall
19
+ end
20
+ }
21
+ end
22
+
23
+ def exec
24
+ exec!.wait
25
+ end
26
+
27
+ end
@@ -0,0 +1,91 @@
1
+
2
+ class Rubish::Command < Rubish::UnixExecutable
3
+
4
+ attr_reader :cmd, :args
5
+ attr_reader :quoted # if true, arguments for exec are not shell expanded.
6
+ def initialize(cmd,args)
7
+ @quoted = false
8
+ @args = args
9
+ @cmd = cmd.to_s
10
+ end
11
+
12
+ def exec_with(i,o,e)
13
+ normalize_args!
14
+ unless pid = Kernel.fork
15
+ # child
16
+ system_exec(i,o,e)
17
+ else
18
+ return [pid]
19
+ end
20
+ end
21
+
22
+ # this method should be called after fork
23
+ def system_exec(i,o,e)
24
+ begin
25
+ # dup2 the given i,o,e to stdin,stdout,stderr
26
+ # close all other file
27
+ Rubish.set_stdioe(i,o,e)
28
+ # exec the command
29
+ if self.quoted
30
+ # use arguments as is
31
+ Kernel.exec self.cmd, *args
32
+ else
33
+ # want shell expansion of arguments
34
+ Kernel.exec "#{self.cmd} #{args.join " "}"
35
+ end
36
+ rescue
37
+ # with just want to kill the child
38
+ # process. When something goes wrong with
39
+ # exec. No cleanup necessary.
40
+ #
41
+ # There's a weird problem with
42
+ # Process.exit(non_zero) raising SystemExit,
43
+ # and that exception somehow reaches the
44
+ # parent process.
45
+ Process.exit!(1)
46
+ end
47
+ end
48
+
49
+ def to_s
50
+ self.inspect
51
+ end
52
+
53
+ def q
54
+ @quoted = true
55
+ self
56
+ end
57
+
58
+ def q!
59
+ @quoted = false
60
+ self
61
+ end
62
+
63
+ def +(arg)
64
+ @args << arg
65
+ self
66
+ end
67
+
68
+ def %(arg)
69
+ @args = [arg]
70
+ self
71
+ end
72
+
73
+ def normalize_args!(args=@args)
74
+ args.map! do |arg|
75
+ case arg
76
+ when Symbol
77
+ "-#{arg.to_s[0..-1]}"
78
+ when Array
79
+ # recursively flatten args
80
+ normalize_args!(arg)
81
+ when String
82
+ arg
83
+ else
84
+ raise "argument to command should be one of Symbol, String, Array "
85
+ end
86
+ end
87
+ args.flatten!
88
+ args
89
+ end
90
+
91
+ end
@@ -0,0 +1,116 @@
1
+
2
+ class Rubish::Arguments
3
+ # integeral key doesn't make sense.
4
+
5
+ attr_reader :args, :keys
6
+ def initialize
7
+ @args = [] # to store the args
8
+ @keys = {} # to store the position of the key arguments
9
+ end
10
+
11
+ def to_s
12
+ @args.flatten.compact!
13
+ @args.join " "
14
+ end
15
+
16
+ def [](key)
17
+ args[keys[key]] if keys.has_key?(key)
18
+ end
19
+
20
+ def <<(obj)
21
+ args << obj
22
+ end
23
+
24
+ def toggle(key,obj=nil)
25
+ if self.has_key?(key)
26
+ # r = args[keys[key]]
27
+ args[keys[key]] = nil
28
+ keys.delete(key)
29
+ return false # kinda weird to return the toggled-off arguments
30
+ else
31
+ args << (obj ? [key,obj] : [key])
32
+ keys[key] = args.length - 1
33
+ return true
34
+ end
35
+ end
36
+
37
+ def set(key,val=nil)
38
+ if self.has_key?(key)
39
+ self.delete(key)
40
+ end
41
+ self.toggle(key,val)
42
+ end
43
+
44
+ def has_key?(key)
45
+ keys.has_key?(key)
46
+ end
47
+
48
+ def push(key,val)
49
+ self.concat(key,[val])
50
+ end
51
+
52
+ def concat(key,array)
53
+ if self.has_key?(key)
54
+ args[keys[key]].concat array
55
+ else
56
+ self.toggle(key,array)
57
+ end
58
+ end
59
+
60
+ def delete(key)
61
+ if self.has_key?(key)
62
+ return args.toggle(key)
63
+ else
64
+ nil
65
+ end
66
+ end
67
+
68
+
69
+ def inspect
70
+ "<#{self.class}: #{self.to_s}>"
71
+ end
72
+ end
73
+
74
+ class Rubish::CommandBuilder < Rubish::Command
75
+ attr_reader :args
76
+ class << self
77
+ def inherited(klass)
78
+ puts "inherited by #{klass}"
79
+ klass.instance_eval do
80
+ def as(name)
81
+ self.instance_eval("def cmd_name; '#{name}'; end")
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ def initialize
88
+ @args = Rubish::Arguments.new
89
+ end
90
+
91
+ def set(key,val=nil)
92
+ args.set(key,val)
93
+ self
94
+ end
95
+
96
+ def toggle(key,val=nil)
97
+ args.toggle(key,val)
98
+ self
99
+ end
100
+
101
+ def opts(v)
102
+ case v
103
+ when Array
104
+ args << v
105
+ when Hash
106
+ v.each do |k,v|
107
+ args.push(k,v)
108
+ end
109
+ end
110
+ self
111
+ end
112
+
113
+ def cmd
114
+ "#{self.class.cmd_name} #{args.to_s}"
115
+ end
116
+ end
@@ -0,0 +1,75 @@
1
+ class Rubish::Context
2
+
3
+ class << self
4
+ def singleton
5
+ @singleton ||= self.new(Rubish::Workspace.global,
6
+ $stdin,$stdout,$stderr)
7
+ end
8
+ alias_method :global, :singleton
9
+
10
+ def current
11
+ Thread.current["rubish.context"] || self.singleton
12
+ end
13
+
14
+ def as_current(context,&block)
15
+ raise "expects a context" unless context.is_a?(Rubish::Context)
16
+ begin
17
+ old_context = Thread.current["rubish.context"]
18
+ Thread.current["rubish.context"] = context
19
+ block.call
20
+ ensure
21
+ Thread.current["rubish.context"] = old_context
22
+ end
23
+ end
24
+ end
25
+
26
+ attr_accessor :i, :o, :err
27
+ attr_accessor :workspace
28
+ attr_reader :pwd # working_directory
29
+ attr_reader :job_control
30
+ attr_reader :parent
31
+
32
+ # prototype style cloning, but only on select attributes
33
+ def initialize(workspace,i=nil,o=nil,err=nil)
34
+ # a cloned context inherits the follow attributes
35
+ @workspace = workspace
36
+ @i = i || Rubish::Context.current.i
37
+ @o = o || Rubish::Context.current.o
38
+ @err = err || Rubish::Context.current.err
39
+ # @pwd = Dir.pwd
40
+
41
+ # not these
42
+ @job_control = Rubish::JobControl.new
43
+ @parent = nil
44
+ end
45
+
46
+ def initialize_copy(from)
47
+ # note that we use the cloned workspace of the parent's workspace.
48
+ initialize(from.workspace.derive,
49
+ from.i, from.o, from.err)
50
+ @job_control = Rubish::JobControl.new
51
+ end
52
+
53
+ def derive(workspace=nil,i=nil,o=nil,err=nil)
54
+ parent = self
55
+ child = parent.clone
56
+ child.instance_eval {
57
+ @parent = parent
58
+ @workspace = workspace if workspace
59
+ @i = i if i
60
+ @o = o if o
61
+ @err = err if err
62
+ }
63
+ return child
64
+ end
65
+
66
+ def eval(string=nil,&block)
67
+ Rubish::Context.as_current(self) {
68
+ if string
69
+ self.workspace.eval(string)
70
+ else
71
+ self.workspace.eval(&block)
72
+ end
73
+ }
74
+ end
75
+ end