ZenHacks 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,18 @@
1
+ *** 1.0.1 / 2005-07-13
2
+
3
+ + 4 minor enhancements:
4
+ + Added Graph#save and edge accessors for customizations.
5
+ + Added Proc#to_ruby in r2c_hacks.
6
+ + Added RubyToRuby#rewrite_defn to support bmethods (read: procs).
7
+ + Added Class#optimize(*methods) to zenoptimize.
8
+ + Added bin/nopaste for cmdline access to nopaste on rafb.net.
9
+ + Added bin/quickbench to generate ruby benchmark templates quickly.
10
+ + 4 bug fixes:
11
+ + Fixed gems for non-gem systems.
12
+ + Fixed minor output problem with RubyToRuby#process_defn.
13
+ + Added some minor (performance) enhancements to zenoptimize.
14
+ + Added requirements to gemspec to quell whining.
15
+
1
16
  *** 1.0.0 / 2005-05-24
2
17
 
3
18
  + 1 major enhancement
@@ -1,8 +1,11 @@
1
1
  History.txt
2
2
  Manifest.txt
3
3
  README.txt
4
+ ZenHacks.gemspec
4
5
  bin/macgraph
6
+ bin/nopaste
5
7
  bin/parse_tree_graph
8
+ bin/quickbench
6
9
  bin/test_stats
7
10
  fixloops-demo.sh
8
11
  lib/OrderedHash.rb
data/README.txt CHANGED
@@ -4,6 +4,11 @@ ZenHacks
4
4
 
5
5
  ** DESCRIPTION:
6
6
 
7
+ A cornucopia of hackery. Toys, Tricks and Tools that have spawned out
8
+ of my other projects (RubyInline, ParseTree, Ruby2C, etc) but don't
9
+ exactly fit there. This includes ZenDebugger, ZenProfiler,
10
+ ZenOptimizer, ruby2ruby, and more.
11
+
7
12
  ZenHacks is a semi-random collection of libs and scripts that just
8
13
  don't belong in a package of their own. Many, if not most, have
9
14
  dependencies on other packages and use, abuse, or extend them in
@@ -0,0 +1,39 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+
5
+ spec = Gem::Specification.new do |s|
6
+
7
+ s.name = 'ZenHacks'
8
+ s.version = '1.0.1'
9
+ s.summary = "Tools and toys of mine that don't have a better home."
10
+
11
+ paragraphs = File.read("README.txt").split(/\n\n+/)
12
+ s.description = paragraphs[3]
13
+ puts s.description
14
+
15
+ s.add_dependency('RubyInline')
16
+ s.add_dependency('ParseTree')
17
+ s.add_dependency('RubyToC')
18
+
19
+ all_files = IO.readlines("Manifest.txt").map {|f| f.chomp }
20
+ s.files = all_files
21
+
22
+ s.bindir = "bin"
23
+ s.executables = all_files.grep(%r%bin/%).map { |f| File.basename(f) }
24
+ puts "Executables = #{s.executables.join(", ")}"
25
+
26
+ s.require_path = 'lib'
27
+
28
+ s.has_rdoc = false # I SUCK - TODO
29
+
30
+ s.author = "Ryan Davis"
31
+ s.email = "ryand-ruby@zenspider.com"
32
+ s.homepage = "http://rubyforge.org/projects/zenhacks/"
33
+ s.rubyforge_project = "zenhacks"
34
+ end
35
+
36
+ if $0 == __FILE__
37
+ Gem.manage_gems
38
+ Gem::Builder.new(spec).build
39
+ end
@@ -0,0 +1,74 @@
1
+ #!/usr/local/bin/ruby -sw
2
+
3
+ require 'net/http'
4
+ require 'pp'
5
+ require 'cgi'
6
+
7
+ languages = %w(C90 C C++ C\# Java Pascal Perl PHP PL/I Python Ruby SQL VB XML Plain\ Text)
8
+ default_language = languages.last
9
+ tab_values = %w(No 2 3 4 5 6 8)
10
+
11
+ $l ||= default_language
12
+ $n ||= ""
13
+ $s ||= ""
14
+ $t ||= tab_values.first
15
+
16
+ lang = $l
17
+ nickname = $n
18
+ description = $s
19
+ tabs = $t
20
+
21
+ text =
22
+ if ARGV.empty? then
23
+ $stdin.read
24
+ else
25
+ File.read(ARGV.shift)
26
+ end
27
+
28
+ data = {
29
+ :lang => lang,
30
+ :nick => nickname,
31
+ :desc => description,
32
+ :cvt_tabs => tabs,
33
+ :text => text,
34
+ }
35
+
36
+ order = %w(lang nick desc cvt_tabs text).map { |s| s.intern }
37
+ data = order.map { |k|
38
+ v=data[k]
39
+ "#{CGI::escape k.to_s}=#{CGI::escape v}"
40
+ }.join('&')
41
+
42
+ headers = {
43
+ 'Content-Type' => 'application/x-www-form-urlencoded',
44
+ 'Referer' => 'http://www.rafb.net/paste/index.html',
45
+ 'Host' => 'www.rafb.net',
46
+ 'Accept' => 'image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, image/tiff, multipart/x-mixed-replace, */*;q=0.1',
47
+ 'Accept-Encoding' => 'bzip2, gzip, deflate, identity',
48
+ 'Accept-Charset' => 'iso-8859-1, utf-8, iso-10646-ucs-2, macintosh, windows-1252, *',
49
+ 'Accept-Language' => 'en, fr;q=0.94, ja;q=0.88, it;q=0.81, de;q=0.75, es;q=0.69, nl;q=0.62, sv;q=0.56, no;q=0.50, da;q=0.44, fi;q=0.38, pt;q=0.31, zh-cn;q=0.25, zh-tw;q=0.19, ko;q=0.12',
50
+ 'Pragma' => 'no-cache',
51
+ 'Cache-Control' => 'max-age=0',
52
+ 'Connection' => 'Keep-Alive',
53
+ 'User-Agent' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.34',
54
+ }
55
+
56
+ Net::HTTP.start('www.rafb.net', 80) { |http|
57
+ response = http.post('/paste/paste.php', data, headers)
58
+
59
+ location = response['location']
60
+
61
+ if location then
62
+ puts "http://www.rafb.net#{location}"
63
+ else
64
+ puts "ERROR:"
65
+ puts "header:"
66
+ p response.header
67
+ puts
68
+ puts "body:"
69
+ puts response.body
70
+ puts "code/message:"
71
+ puts response.code
72
+ puts response.message
73
+ end
74
+ }
@@ -17,14 +17,8 @@ end
17
17
 
18
18
  usage if defined? $h
19
19
 
20
-
21
- #begin
22
- # require 'rubygems'
23
- # require_gem 'ParseTree'
24
- #rescue LoadError
25
- require 'parse_tree'
26
- #end
27
-
20
+ begin require 'rubygems' rescue LoadError end
21
+ require 'parse_tree'
28
22
  require 'sexp_processor'
29
23
 
30
24
  def discover_new_classes_from
@@ -0,0 +1,43 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # TODO: while you are doing this, add an emacs method that toggles
4
+ # between test file and implementation!
5
+
6
+ def usage
7
+ puts "quickbench number-of-benchmarks"
8
+ exit 1
9
+ end
10
+
11
+ # path = ARGV.shift || usage
12
+ count = ARGV.shift.to_i || usage
13
+ usage unless ARGV.empty?
14
+
15
+ require 'benchmark'
16
+
17
+ print <<EOM
18
+ require 'benchmark'
19
+
20
+ MAX=1_000_000
21
+
22
+ Benchmark::bm(20) do |x|
23
+ x.report("null_time") {
24
+ for i in 0..MAX do
25
+ # do nothing
26
+ end
27
+ }
28
+
29
+ EOM
30
+
31
+ count.times do |n|
32
+ print <<"EOM"
33
+ x.report("benchmark-#{n+1}") {
34
+ for i in 0..MAX do
35
+ # insert code here
36
+ end
37
+ }
38
+
39
+ EOM
40
+ end
41
+
42
+ puts "end"
43
+
@@ -5,11 +5,13 @@ class Graph < Hash
5
5
  attr_reader :attribs
6
6
  attr_reader :prefix
7
7
  attr_reader :order
8
- def initialize(name="a_graph")
9
- super() { |h,k| h[k] = [] }
10
- @name = name
8
+ attr_reader :edge
9
+
10
+ def initialize
11
+ super { |h,k| h[k] = [] }
11
12
  @prefix = []
12
13
  @attribs = Hash.new { |h,k| h[k] = [] }
14
+ @edge = Hash.new { |h,k| h[k] = Hash.new { |h2,k2| h2[k2] = [] } }
13
15
  @order = []
14
16
  end
15
17
 
@@ -25,7 +27,7 @@ class Graph < Hash
25
27
  end
26
28
  end
27
29
  end
28
-
30
+
29
31
  def invert
30
32
  result = self.class.new
31
33
  each_pair do |from, to|
@@ -41,14 +43,14 @@ class Graph < Hash
41
43
  end
42
44
  result
43
45
  end
44
-
46
+
45
47
  def keys_by_count
46
48
  counts.sort_by { |x,y| y }.map {|x| x.first }
47
49
  end
48
50
 
49
51
  def to_s
50
52
  result = []
51
- result << "digraph #{@name}"
53
+ result << "digraph absent"
52
54
  result << " {"
53
55
  @prefix.each do |line|
54
56
  result << line
@@ -57,10 +59,20 @@ class Graph < Hash
57
59
  result << " #{node.inspect} [ #{attribs.join(',')} ]"
58
60
  end
59
61
  each_pair do |from, to|
60
- result << " #{from.inspect} -> #{to.inspect};"
62
+ edge = @edge[from][to].join(", ")
63
+ edge = " [ #{edge} ]" unless edge.empty?
64
+ result << " #{from.inspect} -> #{to.inspect}#{edge};"
61
65
  end
62
66
  result << " }"
63
67
  result.join("\n")
64
68
  end
65
69
 
70
+ def save(path, type="png")
71
+ File.open(path + ".dot", "w") do |f|
72
+ f.puts self.to_s
73
+ f.flush
74
+ cmd = "/usr/local/bin/dot -T#{type} #{path}.dot > #{path}.#{type}"
75
+ system cmd
76
+ end
77
+ end
66
78
  end
@@ -1,5 +1,4 @@
1
- #require 'rubygems'
2
- #require_gem 'ParseTree'
1
+ begin require 'rubygems' rescue LoadError end
3
2
  require 'parse_tree'
4
3
  require 'sexp_processor'
5
4
  require 'ruby_to_c'
@@ -10,6 +9,7 @@ class Method
10
9
  if self.inspect =~ /<Method: (.*)\#(.*)>/ then
11
10
  klass = eval $1
12
11
  method = $2.intern
12
+ raise "Couldn't determine class from #{self.inspect}" if klass.nil?
13
13
  return yield(klass, method)
14
14
  else
15
15
  raise "Can't parse signature: #{self.inspect}"
@@ -18,7 +18,7 @@ class Method
18
18
 
19
19
  def to_sexp
20
20
  with_class_and_method_name do |klass, method|
21
- ParseTree.new.parse_tree_for_method(klass, method)
21
+ ParseTree.new(false).parse_tree_for_method(klass, method)
22
22
  end
23
23
  end
24
24
 
@@ -34,3 +34,13 @@ class Method
34
34
  end
35
35
  end
36
36
  end
37
+
38
+ class Proc
39
+ ProcStoreTmp = Class.new unless defined? ProcStoreTmp
40
+ def to_ruby
41
+ ProcStoreTmp.send(:define_method, :myproc, self)
42
+ m = ProcStoreTmp.new.method(:myproc)
43
+ result = m.to_ruby.sub!(/def myproc\(([^\)]+)\)/, 'proc do |\1|')
44
+ return result
45
+ end
46
+ end
@@ -6,9 +6,9 @@ class RubyToRuby < SexpProcessor
6
6
 
7
7
  def self.translate(klass, method=nil)
8
8
  unless method.nil? then
9
- self.new.process(ParseTree.new.parse_tree_for_method(klass, method))
9
+ self.new.process(ParseTree.new(false).parse_tree_for_method(klass, method))
10
10
  else
11
- self.new.process(ParseTree.new.parse_tree(klass).first) # huh? why is the :class node wrapped?
11
+ self.new.process(ParseTree.new(false).parse_tree(klass).first) # huh? why is the :class node wrapped?
12
12
  end
13
13
  end
14
14
 
@@ -115,14 +115,62 @@ class RubyToRuby < SexpProcessor
115
115
  def process_dasgn_curr(exp)
116
116
  exp.shift.to_s
117
117
  end
118
+
119
+ def rewrite_defn(exp)
120
+ exp.shift # :defn
121
+ name = exp.shift
122
+ args = s(:args)
123
+ body = Sexp.from_array exp.shift
124
+
125
+ case body.first
126
+ when :scope, :fbody then
127
+ body = body[1] if body.first == :fbody
128
+ args = body.last[1]
129
+ assert_type args, :args
130
+ assert_type body, :scope
131
+ assert_type body[1], :block
132
+ body.last.delete_at 1
133
+ when :bmethod then
134
+ # BEFORE: [:defn, :bmethod_added, [:bmethod, [:dasgn_curr, :x], ...]]
135
+ # AFTER: [:defn, :bmethod_added, [:args, :x], [:scope, [:block, ...]]]
136
+ body.shift # :bmethod
137
+ # [:dasgn_curr, :x],
138
+ # [:call, [:dvar, :x], :+, [:arglist, [:lit, 1]]]]]
139
+ dasgn = body.shift
140
+ assert_type dasgn, :dasgn_curr
141
+ dasgn.shift # type
142
+ args.push(*dasgn)
143
+ body.find_and_replace_all(:dvar, :lvar)
144
+ if body.first.first == :block then
145
+ body = s(:scope, body.shift)
146
+ else
147
+ body = s(:scope, s(:block, body.shift)) # single statement
148
+ end
149
+ when :dmethod
150
+ # BEFORE: [:defn, :dmethod_added, [:dmethod, :bmethod_maker, ...]]
151
+ # AFTER: [:defn, :dmethod_added, ...]
152
+ body = body[2][1][2] # UGH! FIX
153
+ args = body[1]
154
+ body.delete_at 1
155
+ body = s(:scope, body)
156
+ when :ivar then
157
+ body = s(:scope, s(:block, s(:return, body)))
158
+ when :attrset then
159
+ argname = body.last
160
+ args << :arg
161
+ body = s(:scope, s(:block, s(:return, s(:iasgn, argname, s(:lvar, :arg)))))
162
+ else
163
+ raise "Unknown :defn format: #{name.inspect} #{args.inspect} #{body.inspect}"
164
+ end
165
+
166
+ return s(:defn, name, args, body)
167
+ end
118
168
 
119
169
  def process_defn(exp)
120
170
  name = exp.shift
121
171
  args = process(exp.shift).to_a
122
- args[1..-1] = indent(args[1..-1])
123
- args.join
124
172
  body = indent(process(exp.shift))
125
- return "def #{name}#{args}#{body}end".gsub(/\n\s*\n+/, "\n")
173
+ return "def #{name}#{args}\n#{body}end".gsub(/\n\s*\n+/, "\n")
126
174
  end
127
175
 
128
176
  def process_dot2(exp)
@@ -1,7 +1,19 @@
1
- require 'inline'
1
+ begin require 'rubygems' rescue LoadError end
2
2
  require 'singleton'
3
- require 'ruby_to_c'
3
+ require 'inline'
4
4
  require 'pp'
5
+ require 'ruby_to_c'
6
+
7
+ class Class
8
+ def optimize(*methods)
9
+ methods.each do |method|
10
+ src = RubyToC.translate(self, method)
11
+ class_eval "alias :#{method}_slow :#{method}"
12
+ class_eval "remove_method :#{method}"
13
+ class_eval "inline(:C) { |b| b.c src }"
14
+ end
15
+ end
16
+ end
5
17
 
6
18
  module Inline
7
19
  class Ruby < Inline::C
@@ -23,6 +35,7 @@ class ZenOptimizer
23
35
 
24
36
  include Singleton
25
37
 
38
+ @@signature = :fuck
26
39
  @@threshold = 500
27
40
  @@sacred = {
28
41
  Sexp => true,
@@ -30,6 +43,9 @@ class ZenOptimizer
30
43
  @@skip = Hash.new(false)
31
44
  @@data = Hash.new(0)
32
45
 
46
+ def self.data; @@data; end
47
+ def self.signature; @@signature; end
48
+
33
49
  def self.start_optimizing
34
50
  self.instance.add_event_hook
35
51
  end
@@ -80,6 +96,8 @@ static unsigned long threshold = 0;"
80
96
  prof_event_hook(rb_event_t event, NODE *node,
81
97
  VALUE self, ID mid, VALUE klass) {
82
98
 
99
+ static int optimizing = 0;
100
+
83
101
  if (NIL_P(optimizer_klass))
84
102
  optimizer_klass = rb_path2class("ZenOptimizer");
85
103
  if (NIL_P(data))
@@ -88,34 +106,19 @@ static unsigned long threshold = 0;"
88
106
  skip = rb_cv_get(optimizer_klass, "@@skip");
89
107
  if (threshold == 0)
90
108
  threshold = NUM2ULONG(rb_cv_get(optimizer_klass, "@@threshold"));
109
+ if (optimizing) return;
110
+ optimizing++;
91
111
 
92
112
  switch (event) {
93
113
  case RUBY_EVENT_CALL:
94
114
  {
95
115
  VALUE signature;
96
116
 
97
- #if 0
98
- VALUE mod_name = rb_mod_name(klass);
99
- if (NIL_P(mod_name))
100
- signature = rb_str_new2("Unknown");
101
- else
102
- signature = mod_name;
103
-
104
- rb_str_cat(signature, ".", 1); // TODO: # or .
105
-
106
- char * meth = rb_id2name(mid);
107
- if (meth) {
108
- size_t len = strlen(meth);
109
- rb_str_cat(signature, meth, len);
110
- } else {
111
- rb_str_cat(signature, "unknown", 7);
112
- }
113
- #else
114
117
  signature = rb_ary_new2(2);
115
118
  rb_ary_store(signature, 0, klass);
116
119
  rb_ary_store(signature, 1, ID2SYM(mid));
117
- #endif
118
120
 
121
+ rb_cv_set(optimizer_klass, "@@signature", signature);
119
122
  unsigned long count = NUM2ULONG(rb_hash_aref(data, signature)) + 1;
120
123
 
121
124
  if (count > threshold) {
@@ -128,6 +131,7 @@ static unsigned long threshold = 0;"
128
131
  }
129
132
  break;
130
133
  }
134
+ optimizing--;
131
135
  }
132
136
  EOF
133
137
 
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
 
3
- VERSION='1.0.0' # this is mainly to appease my relese script's requirements.
3
+ VERSION='1.0.1' # this is mainly to appease my relese script's requirements.
4
4
 
5
5
  export GEM_SKIP=RubyInline
6
6
 
metadata CHANGED
@@ -3,15 +3,18 @@ rubygems_version: 0.8.10.1
3
3
  specification_version: 1
4
4
  name: ZenHacks
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.0.0
7
- date: 2005-06-12
6
+ version: 1.0.1
7
+ date: 2005-07-14
8
8
  summary: "Tools and toys of mine that don't have a better home."
9
9
  require_paths:
10
10
  - lib
11
11
  email: ryand-ruby@zenspider.com
12
12
  homepage: http://rubyforge.org/projects/zenhacks/
13
13
  rubyforge_project: zenhacks
14
- description: "** INCLUDES"
14
+ description: "This package is not supported in the same sense that my other packages are, but
15
+ since it is such a fun playground, I am very open to contributions, suggestions,
16
+ and bug fixes. I just can't put this project at the top of my priority list the
17
+ way I can/do the others, so it may take me longer to get to than normal."
15
18
  autorequire:
16
19
  default_executable:
17
20
  bindir: bin
@@ -30,8 +33,11 @@ files:
30
33
  - History.txt
31
34
  - Manifest.txt
32
35
  - README.txt
36
+ - ZenHacks.gemspec
33
37
  - bin/macgraph
38
+ - bin/nopaste
34
39
  - bin/parse_tree_graph
40
+ - bin/quickbench
35
41
  - bin/test_stats
36
42
  - fixloops-demo.sh
37
43
  - lib/OrderedHash.rb
@@ -61,9 +67,40 @@ rdoc_options: []
61
67
  extra_rdoc_files: []
62
68
  executables:
63
69
  - macgraph
70
+ - nopaste
64
71
  - parse_tree_graph
72
+ - quickbench
65
73
  - test_stats
66
74
  extensions: []
67
- requirements:
68
- - Many. Depends on what you want to play with.
69
- dependencies: []
75
+ requirements: []
76
+ dependencies:
77
+ - !ruby/object:Gem::Dependency
78
+ name: RubyInline
79
+ version_requirement:
80
+ version_requirements: !ruby/object:Gem::Version::Requirement
81
+ requirements:
82
+ -
83
+ - ">"
84
+ - !ruby/object:Gem::Version
85
+ version: 0.0.0
86
+ version:
87
+ - !ruby/object:Gem::Dependency
88
+ name: ParseTree
89
+ version_requirement:
90
+ version_requirements: !ruby/object:Gem::Version::Requirement
91
+ requirements:
92
+ -
93
+ - ">"
94
+ - !ruby/object:Gem::Version
95
+ version: 0.0.0
96
+ version:
97
+ - !ruby/object:Gem::Dependency
98
+ name: RubyToC
99
+ version_requirement:
100
+ version_requirements: !ruby/object:Gem::Version::Requirement
101
+ requirements:
102
+ -
103
+ - ">"
104
+ - !ruby/object:Gem::Version
105
+ version: 0.0.0
106
+ version: