green_shoes 0.189.0 → 0.198.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # The XChar library is provided courtesy of Sam Ruby (See
4
+ # http://intertwingly.net/stories/2005/09/28/xchar.rb)
5
+
6
+ # --------------------------------------------------------------------
7
+
8
+ ######################################################################
9
+ module Hpricot
10
+
11
+ ####################################################################
12
+ # XML Character converter, from Sam Ruby:
13
+ # (see http://intertwingly.net/stories/2005/09/28/xchar.rb).
14
+ #
15
+ module XChar # :nodoc:
16
+
17
+ # See
18
+ # http://intertwingly.net/stories/2004/04/14/i18n.html#CleaningWindows
19
+ # for details.
20
+ CP1252 = { # :nodoc:
21
+ 128 => 8364, # euro sign
22
+ 130 => 8218, # single low-9 quotation mark
23
+ 131 => 402, # latin small letter f with hook
24
+ 132 => 8222, # double low-9 quotation mark
25
+ 133 => 8230, # horizontal ellipsis
26
+ 134 => 8224, # dagger
27
+ 135 => 8225, # double dagger
28
+ 136 => 710, # modifier letter circumflex accent
29
+ 137 => 8240, # per mille sign
30
+ 138 => 352, # latin capital letter s with caron
31
+ 139 => 8249, # single left-pointing angle quotation mark
32
+ 140 => 338, # latin capital ligature oe
33
+ 142 => 381, # latin capital letter z with caron
34
+ 145 => 8216, # left single quotation mark
35
+ 146 => 8217, # right single quotation mark
36
+ 147 => 8220, # left double quotation mark
37
+ 148 => 8221, # right double quotation mark
38
+ 149 => 8226, # bullet
39
+ 150 => 8211, # en dash
40
+ 151 => 8212, # em dash
41
+ 152 => 732, # small tilde
42
+ 153 => 8482, # trade mark sign
43
+ 154 => 353, # latin small letter s with caron
44
+ 155 => 8250, # single right-pointing angle quotation mark
45
+ 156 => 339, # latin small ligature oe
46
+ 158 => 382, # latin small letter z with caron
47
+ 159 => 376, # latin capital letter y with diaeresis
48
+ }
49
+
50
+ # See http://www.w3.org/TR/REC-xml/#dt-chardata for details.
51
+ PREDEFINED = {
52
+ 34 => '"', # quotation mark
53
+ 38 => '&', # ampersand
54
+ 60 => '<', # left angle bracket
55
+ 62 => '>' # right angle bracket
56
+ }
57
+ PREDEFINED_U = PREDEFINED.inject({}) { |hsh, (k, v)| hsh[v] = k; hsh }
58
+
59
+ # See http://www.w3.org/TR/REC-xml/#charsets for details.
60
+ VALID = [
61
+ 0x9, 0xA, 0xD,
62
+ (0x20..0xD7FF),
63
+ (0xE000..0xFFFD),
64
+ (0x10000..0x10FFFF)
65
+ ]
66
+ end
67
+
68
+ class << self
69
+ # XML escaped version of chr
70
+ def xchr(str)
71
+ n = XChar::CP1252[str] || str
72
+ case n when *XChar::VALID
73
+ XChar::PREDEFINED[n] or (n<128 ? n.chr : "&##{n};")
74
+ else
75
+ '*'
76
+ end
77
+ end
78
+
79
+ # XML escaped version of to_s
80
+ def xs(str)
81
+ str.to_s.unpack('U*').map {|n| xchr(n)}.join # ASCII, UTF-8
82
+ rescue
83
+ str.to_s.unpack('C*').map {|n| xchr(n)}.join # ISO-8859-1, WIN-1252
84
+ end
85
+
86
+ # XML unescape
87
+ def uxs(str)
88
+ str.to_s.
89
+ gsub(/\&\w+;/) { |x| (XChar::PREDEFINED_U[x] || ??).chr }.
90
+ gsub(/\&\#(\d+);/) { [$1.to_i].pack("U*") }
91
+ end
92
+ end
93
+ end
94
+
data/lib/green_shoes.rb CHANGED
@@ -45,3 +45,4 @@ require_relative 'shoes/manual'
45
45
  autoload :ChipMunk, File.join(Shoes::DIR, 'ext/chipmunk')
46
46
  autoload :Bloops, File.join(Shoes::DIR, 'ext/bloops')
47
47
  autoload :Projector, File.join(Shoes::DIR, 'ext/projector')
48
+ autoload :Hpricot, File.join(Shoes::DIR, 'ext/hpricot')
data/lib/shoes/app.rb CHANGED
@@ -237,7 +237,7 @@ class Shoes
237
237
  end if block_given?
238
238
 
239
239
  @canvas.put eb, args[:left], args[:top]
240
- eb.show_now
240
+ eb.show_all
241
241
  args[:real], args[:app], args[:textview] = eb, self, tv
242
242
  @_eb = EditBox.new args
243
243
  end
@@ -520,6 +520,22 @@ class Shoes
520
520
  shapebase Star, args
521
521
  end
522
522
 
523
+ def arrow *attrs
524
+ args = attrs.last.class == Hash ? attrs.pop : {}
525
+ w = attrs[2]
526
+ args.merge!({left: attrs[0], top: attrs[1], width: w, height: w})
527
+ shape args do
528
+ move_to 0, w*0.5*0.6
529
+ line_to w*0.58, w*0.5*0.6
530
+ line_to w*0.58, w*0.5*0.2
531
+ line_to w, w*0.5
532
+ line_to w*0.58, w*(1-0.5*0.2)
533
+ line_to w*0.58, w*(1-0.5*0.6)
534
+ line_to 0, w*(1-0.5*0.6)
535
+ line_to 0, w*0.5*0.6
536
+ end
537
+ end
538
+
523
539
  def rotate angle
524
540
  @pixbuf_rotate, angle = angle.divmod(90)
525
541
  @pixbuf_rotate %= 4
data/lib/shoes/help.rb CHANGED
@@ -2,6 +2,8 @@ class Manual < Shoes
2
2
  url '/', :index
3
3
  url '/manual/(\d+)', :index
4
4
 
5
+ include Hpricot
6
+
5
7
  def index pnum = 0
6
8
  font LANG == 'ja' ? 'MS UI Gothic' : 'Arial'
7
9
  style Link, underline: false, weight: 'bold'
@@ -13,6 +15,7 @@ class Manual < Shoes
13
15
 
14
16
  def get_title_and_desc pnum
15
17
  chapter, section = PNUMS[pnum]
18
+ return nil unless chapter
16
19
  if section
17
20
  [pnum, DOCS[chapter][1][:sections][section][1][:title],
18
21
  DOCS[chapter][1][:sections][section][1][:description],
@@ -45,6 +48,7 @@ class Manual < Shoes
45
48
  stack{para NL * 4}
46
49
  flow width: 0.2, margin_left: 10 do
47
50
  para *TOC
51
+ para link(fg 'to_html', darkmagenta){html_manual}
48
52
  end
49
53
 
50
54
  flow width: 0.8, margin: [10, 0, 20, 0] do
@@ -76,11 +80,11 @@ class Manual < Shoes
76
80
  text.gsub CODE_RE do |lines|
77
81
  lines = lines.split NL
78
82
  n = lines[1] =~ /\#\!ruby/ ? 2 : 1
79
- code = lines[n...-1].join(NL+' ')
83
+ _code = lines[n...-1].join(NL+' ')
80
84
  flow do
81
85
  background rgb(190, 190, 190), curve: 5
82
- inscription link(fg('Run this', green)){eval mk_executable(code), TOPLEVEL_BINDING}, margin_left: 480
83
- para ' ', fg(code, maroon), NL
86
+ inscription link(fg('Run this', green)){eval mk_executable(_code), TOPLEVEL_BINDING}, margin_left: 480
87
+ para fg(code(' ' + _code), maroon), NL, margin_left: -10
84
88
  end
85
89
  para
86
90
  end
@@ -138,7 +142,7 @@ class Manual < Shoes
138
142
  end
139
143
 
140
144
  def color_page
141
- Shoes::App::COLORS.each do |color, v|
145
+ COLORS.each do |color, v|
142
146
  r, g, b = v
143
147
  c = v.dark? ? white : black
144
148
  flow width: 0.33 do
@@ -151,15 +155,7 @@ class Manual < Shoes
151
155
  end
152
156
 
153
157
  def sample_page
154
- names = Dir[File.join(DIR, '../samples/sample*.rb')].map do |file|
155
- orig_name = File.basename file
156
- dummy_name = orig_name.sub(/sample(.*)\.rb/){
157
- first, second = $1.split('-')
158
- "%02d%s%s" % [first.to_i, ('-' if second), second]
159
- }
160
- [dummy_name, orig_name]
161
- end
162
- names.sort.map(&:last).each do |file|
158
+ mk_sample_names.each do |file|
163
159
  stack width: 80 do
164
160
  inscription file[0...-3]
165
161
  img = image File.join(DIR, "../snapshots/#{file[0..-3]}png"), width: 50, height: 50
@@ -168,6 +164,17 @@ class Manual < Shoes
168
164
  end
169
165
  end
170
166
  end
167
+
168
+ def mk_sample_names
169
+ Dir[File.join(DIR, '../samples/sample*.rb')].map do |file|
170
+ orig_name = File.basename file
171
+ dummy_name = orig_name.sub(/sample(.*)\.rb/){
172
+ first, second = $1.split('-')
173
+ "%02d%s%s" % [first.to_i, ('-' if second), second]
174
+ }
175
+ [dummy_name, orig_name]
176
+ end.sort.map &:last
177
+ end
171
178
 
172
179
  def find_pnum page
173
180
  TOC_LIST.each_with_index do |e, i|
@@ -203,6 +210,154 @@ class Manual < Shoes
203
210
  pnum
204
211
  end
205
212
 
213
+ def html_manual
214
+ dir = ask_save_folder
215
+ return unless dir
216
+ FileUtils.mkdir_p File.join(dir, 'static')
217
+ FileUtils.mkdir_p File.join(dir, 'snapshots')
218
+ %w[gshoes-icon.png shoes-manual-apps.png manual.css code_highlighter.js code_highlighter_ruby.js].
219
+ each{|x| FileUtils.cp "#{DIR}/../static/#{x}", "#{dir}/static"}
220
+ Dir[File.join DIR, '../static/man-*.png'].each{|x| FileUtils.cp x, "#{dir}/static"}
221
+ Dir[File.join DIR, '../snapshots/sample*.png'].each{|x| FileUtils.cp x, "#{dir}/snapshots"}
222
+
223
+ TOC_LIST.length.times do |n|
224
+ num, title, desc, methods = get_title_and_desc n
225
+ open File.join(dir, "#{TOC_LIST[n][0]}.html"), 'w' do |f|
226
+ f.puts mk_html(title, desc, methods, TOC_LIST[n+1], get_title_and_desc(n+1), mk_sidebar_list(num))
227
+ end
228
+ end
229
+ end
230
+
231
+ def mk_html title, desc, methods, next_file, next_title, menu
232
+ man = self
233
+ Hpricot do
234
+ xhtml_transitional do
235
+ head do
236
+ meta :"http-equiv" => "Content-Type", "content" => "text/html; charset=utf-8"
237
+ title "The Green Shoes Manual // #{title}"
238
+ script type: "text/javascript", src: "static/code_highlighter.js"
239
+ script type: "text/javascript", src: "static/code_highlighter_ruby.js"
240
+ style type: "text/css" do
241
+ text "@import 'static/manual.css';"
242
+ end
243
+ end
244
+ body do
245
+ div.main! do
246
+ div.manual! do
247
+ h2 "The Green Shoes Manual #{VERSION}"
248
+ h1 title
249
+
250
+ paras = man.mk_paras desc
251
+ div.intro{p man.manual_p(paras.shift)}
252
+
253
+ html_paragraph = proc do
254
+ paras.each do |str|
255
+ if str =~ CODE_RE
256
+ pre{code.rb $1.gsub(/^\s*?\n/, '')}
257
+ else
258
+ cmd, str = case str
259
+ when /\A==== (.+) ====/; [:h4, $1]
260
+ when /\A=== (.+) ===/; [:h3, $1]
261
+ when /\A== (.+) ==/; [:h2, $1]
262
+ when /\A= (.+) =/; [:h1, $1]
263
+ when /\A\{COLORS\}/
264
+ COLORS.each do |color, v|
265
+ f = v.dark? ? "white" : "black"
266
+ div.color(style: "background: #{color}; color: #{f}"){h3 color; p("rgb(%d, %d, %d)" % v)}
267
+ end
268
+ when /\A\{SAMPLES\}/
269
+ man.mk_sample_names.each do |name|
270
+ name = name[0...-3]
271
+ div.sample do
272
+ h3 name
273
+ p '<a href="snapshots/%s.png"><img src="snapshots/%s.png" alt="%s" border=0 width=50 height=50></a>' % [name, name, name]
274
+ end
275
+ end
276
+ when /\A \* (.+)/m
277
+ ul{$1.split(/^ \* /).each{|x| li{self << man.manual_p(x)}}}
278
+ else
279
+ [:p, str]
280
+ end
281
+ send(cmd){self << man.manual_p(str)} if cmd.is_a?(Symbol)
282
+ end
283
+ end
284
+ end
285
+
286
+ html_paragraph.call
287
+
288
+ methods.each do |m, d|
289
+ n = m.index("\u00BB")
290
+ n ? (sig, val = m[0...n-1], m[n-1..-1]) : (sig, val = m, nil)
291
+ aname = sig[/^[^(=]+=?/].gsub(/\s/, '').downcase
292
+ a name: aname
293
+ div.method do
294
+ a sig, href: "##{aname}"
295
+ text val if val
296
+ end
297
+ div.desc do
298
+ paras = man.mk_paras d
299
+ html_paragraph.call
300
+ end
301
+ end
302
+
303
+ p.next{text "Next: "; a next_title[1], href: "#{next_file[0]}.html"} if next_title
304
+ end
305
+ div.sidebar do
306
+ img src: "static/gshoes-icon.png"
307
+ ul do
308
+ li{a.prime "HELP", href: "./"}
309
+ menu.each do |m|
310
+ li do
311
+ unless m.is_a?(Array)
312
+ a m, href: "#{m}.html"
313
+ else
314
+ ul.sub do
315
+ m.each do |sm|
316
+ li{a sm, href: "#{sm}.html"}
317
+ end
318
+ end
319
+ end
320
+ end
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end
327
+ end.to_html
328
+ end
329
+
330
+ def mk_sidebar_list num
331
+ toc = []
332
+ [0..3, 4..9, 10..16, 17..32, 33..35].each do |r|
333
+ toc.push TOC_LIST[r.first][0]
334
+ toc.push(TOC_LIST[r.first+1..r.last].to_a.map &:first) if r.include?(num)
335
+ end
336
+ toc
337
+ end
338
+
339
+ def manual_p str
340
+ str.gsub(/\n+\s*/, " ").
341
+ gsub(/&/, '&amp;').gsub(/>/, '&gt;').gsub(/>/, '&lt;').gsub(/"/, '&quot;').
342
+ gsub(/`(.+?)`/m, '<code>\1</code>').gsub(/\[\[BR\]\]/i, "<br />\n").
343
+ gsub(/\^(.+?)\^/m, '\1').
344
+ gsub(/'''(.+?)'''/m, '<strong>\1</strong>').gsub(/''(.+?)''/m, '<em>\1</em>').
345
+ gsub(/\[\[((http|https):\/\/\S+?)\]\]/m, '<a href="\1" target="_new">\1</a>').
346
+ gsub(/\[\[((http|https):\/\/\S+?) (.+?)\]\]/m, '<a href="\1" target="_new">\3</a>').
347
+ gsub(/\[\[(\S+?)\]\]/m) do
348
+ ms, mn = $1.split(".", 2)
349
+ if mn
350
+ '<a href="' + ms + '.html#' + mn + '">' + mn + '</a>'
351
+ else
352
+ '<a href="' + ms + '.html">' + ms + '</a>'
353
+ end
354
+ end.
355
+ gsub(/\[\[(\S+?) (.+?)\]\]/m, '<a href="\1.html">\2</a>').
356
+ gsub(/\!(\{[^}\n]+\})?([^!\n]+\.\w+)\!/) do
357
+ '<img src="' + "static/#$2" + '" />'
358
+ end
359
+ end
360
+
206
361
  IMAGE_RE = /\!(\{([^}\n]+)\})?([^!\n]+\.\w+)\!/
207
362
  CODE_RE = /\{{3}(?:\s*\#![^\n]+)?(.+?)\}{3}/m
208
363
  NL = "\n"
@@ -0,0 +1,188 @@
1
+ /* Unobtrustive Code Highlighter By Dan Webb 11/2005
2
+ Version: 0.4
3
+
4
+ Usage:
5
+ Add a script tag for this script and any stylesets you need to use
6
+ to the page in question, add correct class names to CODE elements,
7
+ define CSS styles for elements. That's it!
8
+
9
+ Known to work on:
10
+ IE 5.5+ PC
11
+ Firefox/Mozilla PC/Mac
12
+ Opera 7.23 + PC
13
+ Safari 2
14
+
15
+ Known to degrade gracefully on:
16
+ IE5.0 PC
17
+
18
+ Note: IE5.0 fails due to the use of lookahead in some stylesets. To avoid script errors
19
+ in older browsers use expressions that use lookahead in string format when defining stylesets.
20
+
21
+ This script is inspired by star-light by entirely cunning Dean Edwards
22
+ http://dean.edwards.name/star-light/.
23
+ */
24
+
25
+ // replace callback support for safari.
26
+ if ("a".replace(/a/, function() {return "b"}) != "b") (function(){
27
+ var default_replace = String.prototype.replace;
28
+ String.prototype.replace = function(search,replace){
29
+ // replace is not function
30
+ if(typeof replace != "function"){
31
+ return default_replace.apply(this,arguments)
32
+ }
33
+ var str = "" + this;
34
+ var callback = replace;
35
+ // search string is not RegExp
36
+ if(!(search instanceof RegExp)){
37
+ var idx = str.indexOf(search);
38
+ return (
39
+ idx == -1 ? str :
40
+ default_replace.apply(str,[search,callback(search, idx, str)])
41
+ )
42
+ }
43
+ var reg = search;
44
+ var result = [];
45
+ var lastidx = reg.lastIndex;
46
+ var re;
47
+ while((re = reg.exec(str)) != null){
48
+ var idx = re.index;
49
+ var args = re.concat(idx, str);
50
+ result.push(
51
+ str.slice(lastidx,idx),
52
+ callback.apply(null,args).toString()
53
+ );
54
+ if(!reg.global){
55
+ lastidx += RegExp.lastMatch.length;
56
+ break
57
+ }else{
58
+ lastidx = reg.lastIndex;
59
+ }
60
+ }
61
+ result.push(str.slice(lastidx));
62
+ return result.join("")
63
+ }
64
+ })();
65
+
66
+ var CodeHighlighter = { styleSets : new Array };
67
+
68
+ CodeHighlighter.addStyle = function(name, rules) {
69
+ // using push test to disallow older browsers from adding styleSets
70
+ if ([].push) this.styleSets.push({
71
+ name : name,
72
+ rules : rules,
73
+ ignoreCase : arguments[2] || false
74
+ })
75
+
76
+ function setEvent() {
77
+ // set highlighter to run on load (use LowPro if present)
78
+ if (typeof Event != 'undefined' && typeof Event.onReady == 'function')
79
+ return Event.onReady(CodeHighlighter.init.bind(CodeHighlighter));
80
+
81
+ var old = window.onload;
82
+
83
+ if (typeof window.onload != 'function') {
84
+ window.onload = function() { CodeHighlighter.init() };
85
+ } else {
86
+ window.onload = function() {
87
+ old();
88
+ CodeHighlighter.init();
89
+ }
90
+ }
91
+ }
92
+
93
+ // only set the event when the first style is added
94
+ if (this.styleSets.length==1) setEvent();
95
+ }
96
+
97
+ CodeHighlighter.init = function() {
98
+ if (!document.getElementsByTagName) return;
99
+ if ("a".replace(/a/, function() {return "b"}) != "b") return; // throw out Safari versions that don't support replace function
100
+ // throw out older browsers
101
+
102
+ var codeEls = document.getElementsByTagName("CODE");
103
+ // collect array of all pre elements
104
+ codeEls.filter = function(f) {
105
+ var a = new Array;
106
+ for (var i = 0; i < this.length; i++) if (f(this[i])) a[a.length] = this[i];
107
+ return a;
108
+ }
109
+
110
+ var rules = new Array;
111
+ rules.toString = function() {
112
+ // joins regexes into one big parallel regex
113
+ var exps = new Array;
114
+ for (var i = 0; i < this.length; i++) exps.push(this[i].exp);
115
+ return exps.join("|");
116
+ }
117
+
118
+ function addRule(className, rule) {
119
+ // add a replace rule
120
+ var exp = (typeof rule.exp != "string")?String(rule.exp).substr(1, String(rule.exp).length-2):rule.exp;
121
+ // converts regex rules to strings and chops of the slashes
122
+ rules.push({
123
+ className : className,
124
+ exp : "(" + exp + ")",
125
+ length : (exp.match(/(^|[^\\])\([^?]/g) || "").length + 1, // number of subexps in rule
126
+ replacement : rule.replacement || null
127
+ });
128
+ }
129
+
130
+ function parse(text, ignoreCase) {
131
+ // main text parsing and replacement
132
+ return text.replace(new RegExp(rules, (ignoreCase)?"gi":"g"), function() {
133
+ var i = 0, j = 1, rule;
134
+ while (rule = rules[i++]) {
135
+ if (arguments[j]) {
136
+ // if no custom replacement defined do the simple replacement
137
+ if (!rule.replacement) return "<span class=\"" + rule.className + "\">" + arguments[0] + "</span>";
138
+ else {
139
+ // replace $0 with the className then do normal replaces
140
+ var str = rule.replacement.replace("$0", rule.className);
141
+ for (var k = 1; k <= rule.length - 1; k++) str = str.replace("$" + k, arguments[j + k]);
142
+ return str;
143
+ }
144
+ } else j+= rule.length;
145
+ }
146
+ });
147
+ }
148
+
149
+ function highlightCode(styleSet) {
150
+ // clear rules array
151
+ var parsed, clsRx = new RegExp("(\\s|^)" + styleSet.name + "(\\s|$)");
152
+ rules.length = 0;
153
+
154
+ // get stylable elements by filtering out all code elements without the correct className
155
+ var stylableEls = codeEls.filter(function(item) { return clsRx.test(item.className) });
156
+
157
+ // add style rules to parser
158
+ for (var className in styleSet.rules) addRule(className, styleSet.rules[className]);
159
+
160
+
161
+ // replace for all elements
162
+ for (var i = 0; i < stylableEls.length; i++) {
163
+ // EVIL hack to fix IE whitespace badness if it's inside a <pre>
164
+ if (/MSIE/.test(navigator.appVersion) && stylableEls[i].parentNode.nodeName == 'PRE') {
165
+ stylableEls[i] = stylableEls[i].parentNode;
166
+
167
+ parsed = stylableEls[i].innerHTML.replace(/(<code[^>]*>)([^<]*)<\/code>/i, function() {
168
+ return arguments[1] + parse(arguments[2], styleSet.ignoreCase) + "</code>"
169
+ });
170
+ parsed = parsed.replace(/\n( *)/g, function() {
171
+ var spaces = "";
172
+ for (var i = 0; i < arguments[1].length; i++) spaces+= "&nbsp;";
173
+ return "\n" + spaces;
174
+ });
175
+ parsed = parsed.replace(/\t/g, "&nbsp;&nbsp;&nbsp;&nbsp;");
176
+ parsed = parsed.replace(/\n(<\/\w+>)?/g, "<br />$1").replace(/<br \/>[\n\r\s]*<br \/>/g, "<p><br></p>");
177
+
178
+ } else parsed = parse(stylableEls[i].innerHTML, styleSet.ignoreCase);
179
+
180
+ stylableEls[i].innerHTML = parsed;
181
+ }
182
+ }
183
+
184
+ // run highlighter on all stylesets
185
+ for (var i=0; i < this.styleSets.length; i++) {
186
+ highlightCode(this.styleSets[i]);
187
+ }
188
+ }