dmeiz-croc 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,6 @@
1
+ /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems
2
+ /Library/Ruby/Gems/1.8/gems
3
+ ruby -Ilib bin/croc
4
+
5
+ TODO
6
+ - verbose output to show what classes aren't being found when indexing
data/bin/croc ADDED
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+ require "croc"
4
+
5
+ $gems = []
6
+ $classes = {}
7
+ $methods = []
8
+
9
+ install_assets
10
+
11
+ specs = get_specs
12
+
13
+ homes = {}
14
+ specs.each do |spec|
15
+ spec.loaded_from =~ /^(.+)\/specifications/
16
+ homes[$1] = true
17
+ end
18
+
19
+ # find gem home
20
+ $home = homes.keys.detect { |home| home !~ /^\/System/ }
21
+ $rdoc_home = File.join($home, "doc")
22
+ $gem_home = File.join($home, "gems")
23
+ $croc_home = File.join(user_home_dir, ".croc")
24
+
25
+ puts "Indexing gems in #{$gem_home}"
26
+
27
+ # install system gems
28
+ gems_to_install = specs.select { |spec| spec.loaded_from =~ /^\/System/ }
29
+
30
+ unless gems_to_install.empty?
31
+ puts "It looks like you're using a Mac and these gems are installed under /System:"
32
+ puts
33
+ puts " #{gems_to_install.collect {|spec| "#{spec.name}-#{spec.version}"}.join(" ")}"
34
+ puts
35
+ puts "Croc can't index these, but installing them in your main gems directory"
36
+ puts "should solve the problem. Install them (may require sudo)? (y/n)"
37
+ if gets.strip == "y"
38
+ gems_to_install.each do |spec|
39
+ puts "Installing #{spec.name}-#{spec.version}"
40
+ `gem install -v #{spec.version} #{spec.name}`
41
+ end
42
+ else
43
+ specs = specs - gems_to_install
44
+ end
45
+ end
46
+
47
+ # install rdocs
48
+ rdocs_to_install = specs.select { |spec| !File.exists?(File.join($rdoc_home, "#{spec.name}-#{spec.version}", "rdoc"))}
49
+
50
+ unless rdocs_to_install.empty?
51
+ puts "These gems have rdocs, but they're not installed:"
52
+ puts
53
+ puts " #{rdocs_to_install.collect {|spec| "#{spec.name}-#{spec.version}"}.join(" ")}"
54
+ puts
55
+ puts "Install them (may require sudo)? (y/n)"
56
+ if gets.strip == "y"
57
+ rdocs_to_install.each do |spec|
58
+ puts "Installing rdocs for #{spec.name}-#{spec.version}"
59
+ `sudo gem rdoc -v #{spec.version} #{spec.name}`
60
+ end
61
+ else
62
+ specs = specs - rdocs_to_install
63
+ end
64
+ end
65
+
66
+ croc_rdoc_dir = File.join($croc_home, "rdoc")
67
+ unless File.exist?(File.join(croc_rdoc_dir, "ruby"))
68
+ puts "Install Ruby and Stdlib rdocs from www.ruby-doc.org? (y/n)"
69
+ if gets.strip == "y"
70
+ install_rdocs("http://www.ruby-doc.org/download/ruby-1.8.6-core-rdocs.tgz", "core-1.8.6_HEAD", "ruby")
71
+
72
+ Dir.chdir(croc_rdoc_dir)
73
+ puts "Installing http://www.ruby-doc.org/download/stdlib/ruby-doc-stdlib-0.10.1.tgz"
74
+ tgz_file = File.join(croc_rdoc_dir, "dest.tgz")
75
+ download("http://www.ruby-doc.org/download/stdlib/ruby-doc-stdlib-0.10.1.tgz", tgz_file)
76
+ `tar xzf #{tgz_file}`
77
+ src_file = File.join(croc_rdoc_dir, "ruby-doc-stdlib-0.10.1")
78
+ libdoc_dir = File.join(src_file, "stdlib", "libdoc")
79
+ Dir.chdir(libdoc_dir)
80
+ Dir.glob("**/index.html").each do |f|
81
+ f = File.split(f)[0]
82
+ move_to = File.split(f)[0].split(File::SEPARATOR).join('-')
83
+ File.move(File.join(libdoc_dir, f), File.join(croc_rdoc_dir, move_to))
84
+ end
85
+ File.delete(tgz_file)
86
+ FileUtils.rm_r(src_file)
87
+ else
88
+ specs = specs - rdocs_to_install
89
+ end
90
+ end
91
+
92
+ Dir.chdir(File.join(user_home_dir, ".croc", "rdoc"))
93
+ Dir.glob("*").each do |name|
94
+ next if name == "." || name == ".."
95
+ index_rdoc(name, File.join(Dir.pwd, name))
96
+ end
97
+
98
+ specs.each { |spec| index_rdoc(spec.name, File.join($rdoc_home, "#{spec.name}-#{spec.version}", "rdoc")) }
99
+
100
+ idx = -1
101
+ File.open(File.join(user_home_dir, ".croc", "data.js"), "w") do |f|
102
+ f.puts "objs = ["
103
+ $gems.each do |gem|
104
+ f.puts " {t: 'g', p: null, n: '#{gem[:name]}', l: '#{gem[:name].downcase}', u: '#{gem[:dir]}'},"
105
+ idx += 1
106
+ gidx = idx
107
+ gem[:classes].each_pair do |key, value|
108
+ f.puts " {t: 'c', p: #{gidx}, n: '#{key}', l: '#{key.downcase}', u: '#{value[:url]}'},"
109
+ idx += 1
110
+ cidx = idx
111
+ value[:methods].each do |method|
112
+ f.puts " {t: 'm', p: #{cidx}, n: '#{method[:name]}', l: '#{method[:name].downcase}', u: '#{method[:url]}'},"
113
+ idx += 1
114
+ end
115
+ end
116
+ end
117
+ f.puts "];"
118
+ end
119
+
120
+ puts "Bookmark file://#{File.join(user_home_dir, ".croc", "index.html")}"
data/lib/croc.rb ADDED
@@ -0,0 +1,128 @@
1
+ require "rubygems"
2
+ require "hpricot"
3
+ require "ftools"
4
+
5
+ # Figure out where rdocs are installed.
6
+ def find_gem_home
7
+ if File.exists?("/Library/Ruby/Gems/1.8/gems")
8
+ return "/Library/Ruby/Gems/1.8/gems"
9
+ end
10
+ end
11
+
12
+ # Returns the user's home directory as a string.
13
+ def user_home_dir
14
+ ENV["HOME"]
15
+ end
16
+
17
+ # Creates ~/.croc and installs assets from public directory.
18
+ def install_assets
19
+ croc_dir = File.join(user_home_dir, ".croc")
20
+ unless File.exists?(croc_dir)
21
+ Dir.mkdir(croc_dir)
22
+ Dir.mkdir(File.join(croc_dir, "rdoc"))
23
+ end
24
+
25
+ public_dir = File.join(File.dirname(__FILE__), "..", "public")
26
+ Dir.new(public_dir).each do |f|
27
+ next if f == "." || f == ".."
28
+ File.copy(File.join(public_dir, f), File.join(croc_dir, f))
29
+ end
30
+ end
31
+
32
+ # Print installed gems and whether rdocs are available and indeed installed.
33
+ def print_gems
34
+ Gem.source_index.search(nil).each do |spec|
35
+ puts "#{spec.name} #{spec.version} #{spec.has_rdoc? ? "has rdoc" : ""} #{File.exists?(rdoc_dir) ? "and it exists" : "but it doesn't exist"}"
36
+ end
37
+ end
38
+
39
+ # Collect specs for most recent version of all installed gems.
40
+ def get_specs
41
+ specs = {}
42
+ Gem.source_index.search(nil).each do |spec|
43
+ next unless spec.has_rdoc?
44
+ if specs[spec.name]
45
+ specs[spec.name] = spec if (spec.version <=> specs[spec.name].version) > 0
46
+ else
47
+ specs[spec.name] = spec
48
+ end
49
+ end
50
+ specs.values
51
+ end
52
+
53
+ def index_rdoc(name, rdoc_dir)
54
+ unless File.exists?(rdoc_dir)
55
+ puts "WARN Couldn't find rdoc dir #{rdoc_dir}"
56
+ return
57
+ end
58
+
59
+ methods_file = File.join(rdoc_dir, "fr_method_index.html")
60
+ unless File.exists?(methods_file)
61
+ puts "ERROR Couldn't find #{methods_file}"
62
+ end
63
+
64
+ classes_file = File.join(rdoc_dir, "fr_class_index.html")
65
+ unless File.exists?(classes_file)
66
+ puts "ERROR Couldn't find #{classes_file}"
67
+ end
68
+
69
+ # collect gem
70
+ gem = {:name => name, :dir => rdoc_dir, :classes => {}}
71
+ $gems << gem
72
+
73
+ # collect classes
74
+ doc = Hpricot(open(classes_file))
75
+ (doc/"#index-entries a").each do |el|
76
+ klass = el.inner_html
77
+
78
+ if $classes[klass]
79
+ puts "Already have class #{klass}"
80
+ else
81
+ gem[:classes][klass] = {:name => klass, :url => el["href"], :methods => []}
82
+ end
83
+ end
84
+
85
+ # collect methods
86
+ doc = Hpricot(open(methods_file))
87
+ (doc/"#index-entries a").each do |el|
88
+ if el.inner_html =~ /(\S+)\s+\((\S+)\)/
89
+ method = $1
90
+ if klass = gem[:classes][$2]
91
+ el["href"] =~ /#(.*)$/
92
+ url = $1
93
+ klass[:methods] << {:name => method, :class => klass, :url => url}
94
+ else
95
+ # puts %Q(Couldn't find class "#{$2} for method #{method}")
96
+ end
97
+ else
98
+ # puts %Q(Couldn't get method and class from "#{el.inner_html}")
99
+ end
100
+ end
101
+
102
+ puts "Indexed #{name}"
103
+ end
104
+
105
+ def download(url, dest)
106
+ File.open(dest, "w") do |f|
107
+ url = URI.parse(url)
108
+ http = Net::HTTP.new(url.host, url.port)
109
+ http.request_get(url.path) do |resp|
110
+ resp.read_body do |s|
111
+ f.write(s)
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ def install_rdocs(url, src_dir_name, dest_dir_name)
118
+ croc_rdoc_dir = File.join($croc_home, "rdoc")
119
+ Dir.chdir(croc_rdoc_dir)
120
+ puts "Installing #{url}"
121
+ tgz_file = File.join(croc_rdoc_dir, "dest.tgz")
122
+ src_file = File.join(croc_rdoc_dir, src_dir_name)
123
+ dest_file = File.join(croc_rdoc_dir, dest_dir_name)
124
+ download(url, tgz_file)
125
+ `tar xzf #{tgz_file}`
126
+ File.rename(src_file, dest_file)
127
+ File.delete(tgz_file)
128
+ end
data/public/about.html ADDED
@@ -0,0 +1,46 @@
1
+ <html>
2
+ <head>
3
+ <style>
4
+ th {
5
+ text-align: left;
6
+ }
7
+ </style>
8
+ </head>
9
+ <body>
10
+ <h1>croc</h1>
11
+ <p>
12
+ Quick access to your locally installed rdocs.
13
+ </p>
14
+
15
+ <h2>Examples with rspec</h2>
16
+ <table>
17
+ <tr>
18
+ <th>test</th>
19
+ <td>Gems, classes and methods that contain <em>test</em></td>
20
+ </tr>
21
+ <tr>
22
+ <th>test_finished.</th>
23
+ <td>Classes and methods named exactly <em>test_finished</em></td>
24
+ </tr>
25
+ <tr>
26
+ <th>rsp test</th>
27
+ <td>Classes and methods that contain <em>test</em> in gems that contain <em>rsp</em></td>
28
+ </tr>
29
+ <tr>
30
+ <th>rsp test_finished.</th>
31
+ <td>Classes and methods named exactly <em>test_finished</em> in gems that contain <em>rsp</em></td>
32
+ </tr>
33
+ </table>
34
+
35
+ <h2>Install your own rdocs</h2>
36
+ <p>
37
+ Copy your rdocs directory to ~/.croc/rdoc and make sure it's named
38
+ something sensible. Rerun croc.
39
+ </p>
40
+
41
+ <h2>About</h2>
42
+ Copyright 2008 <a href="http://blog.methodhead.com">Dan Hensgen</a>.
43
+ Feeback appreciated at
44
+ <a href="mailto:dan@methodhead.com">dan@methodhead.com</a>.
45
+ </body>
46
+ </html>
data/public/index.html ADDED
@@ -0,0 +1,189 @@
1
+ <html>
2
+ <head>
3
+ <script type="text/javascript" src="jquery.js"></script>
4
+ <script type="text/javascript" src="jquery.dimensions.js"></script>
5
+ <script type="text/javascript" src="data.js"></script>
6
+ <script>
7
+ suggestions = [];
8
+
9
+ function find(q) {
10
+ if (q == null || jQuery.trim(q).length == 0) {
11
+ return [];
12
+ }
13
+
14
+ gemPart = null;
15
+ if (q.indexOf(' ') > 0) {
16
+ a = q.split(/\s+/)
17
+ gemPart = a[0];
18
+ q = a[1];
19
+ }
20
+
21
+ var sugs = [];
22
+ var includedGems = {};
23
+ var parentGems = {};
24
+
25
+ if (gemPart) {
26
+ for (i in objs) {
27
+ o = objs[i];
28
+ if (o.t == "g") {
29
+ if (o.l.indexOf(gemPart) >= 0) {
30
+ parentGems[i] = true;
31
+ }
32
+ }
33
+ }
34
+ }
35
+
36
+ for (i in objs) {
37
+ o = objs[i];
38
+ if ((q[q.length - 1] == '.' && o.l == q.substr(0, q.length - 1)) || o.l.indexOf(q) >= 0) {
39
+ if (o.t == "c") {
40
+ if (!gemPart || parentGems[o.p]) {
41
+ if (!includedGems[o.p]) {
42
+ includedGems[o.p] = true;
43
+ sugs.push(objs[o.p]);
44
+ }
45
+ sugs.push(o);
46
+ }
47
+ }
48
+ else if (o.t == "m") {
49
+ if (!gemPart || parentGems[objs[o.p].p]) {
50
+ if (!includedGems[objs[o.p].p]) {
51
+ includedGems[objs[o.p].p] = true;
52
+ sugs.push(objs[objs[o.p].p])
53
+ }
54
+ sugs.push(o);
55
+ }
56
+ }
57
+ else {
58
+ if (!gemPart || parentGems[i]) {
59
+ includedGems[i] = true;
60
+ sugs.push(o);
61
+ }
62
+ }
63
+
64
+ if (sugs.length > 50) {
65
+ sugs.push(0)
66
+ break;
67
+ }
68
+ }
69
+ }
70
+
71
+ return sugs;
72
+ }
73
+
74
+ function resultsToHtml(results) {
75
+ html = '';
76
+ jQuery.each(results, function(i, o) {
77
+ if (o == 0) {
78
+ html += '<div>...</div>';
79
+ }
80
+ else {
81
+ switch (o.t) {
82
+ case "g":
83
+ html += '<div class="gem"><a target="iframe" href="file://' + o.u + '/index.html">' + o.n + '</a></div>'; break;
84
+ case "c":
85
+ html += '<div class="class-or-method"><a target="iframe" href="file://' + objs[o.p].u + '/' + o.u + '">' + o.n + '</a></div>'; break;
86
+ case "m":
87
+ html += '<div class="class-or-method"><a target="iframe" href="file://' + objs[objs[o.p].p].u + '/' + objs[o.p].u + '#' + o.u + '">' + o.n + '</a>&nbsp;(' + objs[o.p].n + ')</div>'; break;
88
+ }
89
+ }
90
+ });
91
+
92
+ return html;
93
+ }
94
+
95
+ function sizeElements() {
96
+ $('#suggestions').css('top', $('input').position()['top'] + $('input').outerHeight() + 'px');
97
+ $('#iframe').css('height', $(window).height() - $('input').outerHeight() - 5 + 'px' );
98
+ $('#iframe').css('width', $(window).width() - 5 + 'px' );
99
+ }
100
+
101
+ $(document).ready(function(){
102
+ sizeElements();
103
+
104
+ $(document).keyup(function(e) {
105
+ if (e.keyCode == 27) {
106
+ $('#suggestions').hide();
107
+ }
108
+ });
109
+
110
+ $('iframe').keyup(function(e) {
111
+ if (e.keyCode == 27) {
112
+ $('#suggestions').hide();
113
+ }
114
+ });
115
+
116
+ // search and update results
117
+ $('input').keyup(function(e) {
118
+ if (e.keyCode == 27) {
119
+ return;
120
+ }
121
+
122
+ matches = find(e.target.value.toLowerCase());
123
+
124
+ html = resultsToHtml(matches);
125
+
126
+ if (matches.length > 0) {
127
+ $('#suggestions').html(html).show();
128
+ }
129
+ else {
130
+ $('#suggestions').hide();
131
+ }
132
+ });
133
+
134
+ // hide suggestions if user clicks on a link
135
+ $('#suggestions').click(function(e) {
136
+ if (e.target.nodeName == "A") {
137
+ $('#suggestions').hide();
138
+ $('#recents').prepend('&nbsp;&nbsp;<a target="iframe" href="' + e.target.href + '">' + e.target.innerHTML + '</a>');
139
+ }
140
+ });
141
+
142
+ $('input').focus();
143
+
144
+ $('input').focus(function() {
145
+ if ($('#suggestions').innerHTML != "") {
146
+ $('#suggestions').show();
147
+ }
148
+ });
149
+ });
150
+ </script>
151
+
152
+ <style>
153
+ * {
154
+ margin: 0;
155
+ font: 9pt sans-serif;
156
+ }
157
+ body {
158
+ margin: 0;
159
+ padding: 0;
160
+ }
161
+
162
+ #suggestions {
163
+ border: 1px solid #bbb;
164
+ position: absolute;
165
+ background-color: #fff;
166
+ color: #aaa;
167
+ padding: 3px;
168
+ }
169
+
170
+ #suggestions div.gem {
171
+ font-weight: bold;
172
+ }
173
+
174
+ #suggestions div.class-or-method {
175
+ padding-left: 1em;
176
+ }
177
+ </style>
178
+ </head>
179
+ <body>
180
+ <form>
181
+ <input>
182
+ <span id="recents"></span>
183
+ <div id="suggestions" style="display:none">
184
+ </div>
185
+ </form>
186
+ <iframe id="iframe" name="iframe" src="about.html">
187
+ </iframe>
188
+ </body>
189
+ </html>
@@ -0,0 +1,119 @@
1
+ /* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
2
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
3
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
4
+ *
5
+ * $LastChangedDate: 2007-12-20 08:46:55 -0600 (Thu, 20 Dec 2007) $
6
+ * $Rev: 4259 $
7
+ *
8
+ * Version: 1.2
9
+ *
10
+ * Requires: jQuery 1.2+
11
+ */
12
+
13
+ (function($){
14
+
15
+ $.dimensions = {
16
+ version: '1.2'
17
+ };
18
+
19
+ // Create innerHeight, innerWidth, outerHeight and outerWidth methods
20
+ $.each( [ 'Height', 'Width' ], function(i, name){
21
+
22
+ // innerHeight and innerWidth
23
+ $.fn[ 'inner' + name ] = function() {
24
+ if (!this[0]) return;
25
+
26
+ var torl = name == 'Height' ? 'Top' : 'Left', // top or left
27
+ borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
28
+
29
+ return this.is(':visible') ? this[0]['client' + name] : num( this, name.toLowerCase() ) + num(this, 'padding' + torl) + num(this, 'padding' + borr);
30
+ };
31
+
32
+ // outerHeight and outerWidth
33
+ $.fn[ 'outer' + name ] = function(options) {
34
+ if (!this[0]) return;
35
+
36
+ var torl = name == 'Height' ? 'Top' : 'Left', // top or left
37
+ borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
38
+
39
+ options = $.extend({ margin: false }, options || {});
40
+
41
+ var val = this.is(':visible') ?
42
+ this[0]['offset' + name] :
43
+ num( this, name.toLowerCase() )
44
+ + num(this, 'border' + torl + 'Width') + num(this, 'border' + borr + 'Width')
45
+ + num(this, 'padding' + torl) + num(this, 'padding' + borr);
46
+
47
+ return val + (options.margin ? (num(this, 'margin' + torl) + num(this, 'margin' + borr)) : 0);
48
+ };
49
+ });
50
+
51
+ // Create scrollLeft and scrollTop methods
52
+ $.each( ['Left', 'Top'], function(i, name) {
53
+ $.fn[ 'scroll' + name ] = function(val) {
54
+ if (!this[0]) return;
55
+
56
+ return val != undefined ?
57
+
58
+ // Set the scroll offset
59
+ this.each(function() {
60
+ this == window || this == document ?
61
+ window.scrollTo(
62
+ name == 'Left' ? val : $(window)[ 'scrollLeft' ](),
63
+ name == 'Top' ? val : $(window)[ 'scrollTop' ]()
64
+ ) :
65
+ this[ 'scroll' + name ] = val;
66
+ }) :
67
+
68
+ // Return the scroll offset
69
+ this[0] == window || this[0] == document ?
70
+ self[ (name == 'Left' ? 'pageXOffset' : 'pageYOffset') ] ||
71
+ $.boxModel && document.documentElement[ 'scroll' + name ] ||
72
+ document.body[ 'scroll' + name ] :
73
+ this[0][ 'scroll' + name ];
74
+ };
75
+ });
76
+
77
+ $.fn.extend({
78
+ position: function() {
79
+ var left = 0, top = 0, elem = this[0], offset, parentOffset, offsetParent, results;
80
+
81
+ if (elem) {
82
+ // Get *real* offsetParent
83
+ offsetParent = this.offsetParent();
84
+
85
+ // Get correct offsets
86
+ offset = this.offset();
87
+ parentOffset = offsetParent.offset();
88
+
89
+ // Subtract element margins
90
+ offset.top -= num(elem, 'marginTop');
91
+ offset.left -= num(elem, 'marginLeft');
92
+
93
+ // Add offsetParent borders
94
+ parentOffset.top += num(offsetParent, 'borderTopWidth');
95
+ parentOffset.left += num(offsetParent, 'borderLeftWidth');
96
+
97
+ // Subtract the two offsets
98
+ results = {
99
+ top: offset.top - parentOffset.top,
100
+ left: offset.left - parentOffset.left
101
+ };
102
+ }
103
+
104
+ return results;
105
+ },
106
+
107
+ offsetParent: function() {
108
+ var offsetParent = this[0].offsetParent;
109
+ while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && $.css(offsetParent, 'position') == 'static') )
110
+ offsetParent = offsetParent.offsetParent;
111
+ return $(offsetParent);
112
+ }
113
+ });
114
+
115
+ function num(el, prop) {
116
+ return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;
117
+ };
118
+
119
+ })(jQuery);