ZenHacks 1.0.0 → 1.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.
@@ -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: