dmeiz-croc 0.9.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/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);