rascut 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +18 -0
- data/README.txt +59 -0
- data/Rakefile +23 -0
- data/bin/rascut +10 -0
- data/lib/rascut/command.rb +148 -0
- data/lib/rascut/config.rb +82 -0
- data/lib/rascut/fcsh_wrapper.rb +109 -0
- data/lib/rascut/file_observer.rb +160 -0
- data/lib/rascut/httpd.rb +304 -0
- data/lib/rascut/logger.rb +18 -0
- data/lib/rascut/plugin/base.rb +19 -0
- data/lib/rascut/plugin/write_fcsh_error_output.rb +31 -0
- data/lib/rascut.rb +9 -0
- data/test/test_file_observer.rb +90 -0
- data/test/test_rascut.rb +0 -0
- data/vendor/js/swfobject.js +8 -0
- data/vendor/ruby/expect.rb +36 -0
- metadata +111 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
bin/rascut
|
6
|
+
lib/rascut.rb
|
7
|
+
lib/rascut/command.rb
|
8
|
+
lib/rascut/config.rb
|
9
|
+
lib/rascut/fcsh_wrapper.rb
|
10
|
+
lib/rascut/file_observer.rb
|
11
|
+
lib/rascut/httpd.rb
|
12
|
+
lib/rascut/logger.rb
|
13
|
+
lib/rascut/plugin/base.rb
|
14
|
+
lib/rascut/plugin/write_fcsh_error_output.rb
|
15
|
+
vendor/ruby/expect.rb
|
16
|
+
vendor/js/swfobject.js
|
17
|
+
test/test_rascut.rb
|
18
|
+
test/test_file_observer.rb
|
data/README.txt
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
rascut
|
2
|
+
by Yuichi Tateno
|
3
|
+
|
4
|
+
== DESCRIPTION:
|
5
|
+
|
6
|
+
Rascut is Ruby ActionSCript UTility :D
|
7
|
+
|
8
|
+
== FEATURES/PROBLEMS:
|
9
|
+
|
10
|
+
|
11
|
+
== SYNOPSIS:
|
12
|
+
|
13
|
+
* 1. flex2sdk and fcwrap setting.
|
14
|
+
* 2. $ rascut -s MyScript.as
|
15
|
+
* 3. Browser access http://localhost:3001/
|
16
|
+
|
17
|
+
== REQUIREMENTS:
|
18
|
+
|
19
|
+
* hoe
|
20
|
+
* rack
|
21
|
+
* mongrel
|
22
|
+
* rake
|
23
|
+
|
24
|
+
== INSTALL:
|
25
|
+
|
26
|
+
* gem install rascut
|
27
|
+
|
28
|
+
== OTHER:
|
29
|
+
* vendor/js/swfobject.js is SWFObject by http://blog.deconcept.com/swfobject/
|
30
|
+
|
31
|
+
== LICENSE:
|
32
|
+
|
33
|
+
(The MIT License)
|
34
|
+
|
35
|
+
Copyright (c) 2007 Yuichi Tateno
|
36
|
+
|
37
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
38
|
+
a copy of this software and associated documentation files (the
|
39
|
+
'Software'), to deal in the Software without restriction, including
|
40
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
41
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
42
|
+
permit persons to whom the Software is furnished to do so, subject to
|
43
|
+
the following conditions:
|
44
|
+
|
45
|
+
The above copyright notice and this permission notice shall be
|
46
|
+
included in all copies or substantial portions of the Software.
|
47
|
+
|
48
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
49
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
50
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
51
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
52
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
53
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
54
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
55
|
+
|
56
|
+
== SPECIAL THANKS
|
57
|
+
Thank you feedback!
|
58
|
+
|
59
|
+
id:os0x, yugui, id:wanpark, saqoosha, id:ameema
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
$LOAD_PATH << './lib'
|
6
|
+
require './lib/rascut.rb'
|
7
|
+
|
8
|
+
Hoe.new('rascut', Rascut::VERSION) do |p|
|
9
|
+
p.rubyforge_name = 'hotchpotch'
|
10
|
+
p.author = 'yuichi tateno'
|
11
|
+
p.email = 'hotchpotch@nononospam@gmail.com'
|
12
|
+
p.summary = 'Ruby ActionSCript UTility'
|
13
|
+
p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
14
|
+
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
15
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
16
|
+
|
17
|
+
p.extra_deps << ['mongrel']
|
18
|
+
p.extra_deps << ['rake']
|
19
|
+
p.extra_deps << ['hoe']
|
20
|
+
p.extra_deps << ['rack']
|
21
|
+
end
|
22
|
+
|
23
|
+
# vim: syntax=Ruby
|
data/bin/rascut
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'rascut/fcsh_wrapper'
|
3
|
+
require 'rascut/logger'
|
4
|
+
require 'rascut/config'
|
5
|
+
require 'pathname'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
module Rascut
|
9
|
+
class Command
|
10
|
+
def initialize
|
11
|
+
@logger = Logger.new(STDOUT)
|
12
|
+
end
|
13
|
+
attr_accessor :logger
|
14
|
+
|
15
|
+
def run(argv)
|
16
|
+
@config = Config.new
|
17
|
+
|
18
|
+
if ENV['HOME']
|
19
|
+
home = Pathname.new ENV['HOME']
|
20
|
+
end
|
21
|
+
|
22
|
+
home.join('.rascut').mkpath if home
|
23
|
+
|
24
|
+
if home && home.join('.rascutrc').readable?
|
25
|
+
@config.merge_config home.join('.rascutrc')
|
26
|
+
end
|
27
|
+
|
28
|
+
if File.readable?('.rascut')
|
29
|
+
@config.merge_config('.rascut')
|
30
|
+
end
|
31
|
+
|
32
|
+
@config.parse_argv!(argv)
|
33
|
+
|
34
|
+
unless @target_script = argv.first
|
35
|
+
warn 'Target script is not found.'
|
36
|
+
Kernel::exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
@root = Pathname.new(@target_script).dirname.realpath
|
40
|
+
@wrapper = FcshWrapper.new(@target_script, @config)
|
41
|
+
|
42
|
+
start_server if @config[:server]
|
43
|
+
setting_signals
|
44
|
+
@wrapper.hooks[:compile_success] << method(:compile_success_proc)
|
45
|
+
|
46
|
+
|
47
|
+
if @config[:file_observing]
|
48
|
+
@file_observer = FileObserver.new(@config[:observe_files],
|
49
|
+
:interval => @config[:interval],
|
50
|
+
:ext => @config[:ext],
|
51
|
+
:logger => @config[:logger],
|
52
|
+
:update_handler => method(:file_update_handler))
|
53
|
+
@file_observer.run
|
54
|
+
end
|
55
|
+
|
56
|
+
read_log_loop if @config[:flashlog]
|
57
|
+
|
58
|
+
init_plugins
|
59
|
+
|
60
|
+
@wrapper.compile
|
61
|
+
#readline_loop
|
62
|
+
Thread.stop
|
63
|
+
end
|
64
|
+
attr_reader :config, :root, :target_script, :wrapper, :file_observer
|
65
|
+
|
66
|
+
def init_plugins
|
67
|
+
@config[:plugin].each do |name|
|
68
|
+
klass_name = name.gsub(/(^|_)(.)/) { $2.upcase }
|
69
|
+
logger.info "Load Plugin: #{klass_name}"
|
70
|
+
require "rascut/plugin/#{name}"
|
71
|
+
::Rascut::Plugin.const_get(klass_name).new(self).run
|
72
|
+
end if @config[:plugin]
|
73
|
+
end
|
74
|
+
|
75
|
+
def file_update_handler
|
76
|
+
@wrapper.compile
|
77
|
+
end
|
78
|
+
|
79
|
+
def read_log_loop
|
80
|
+
log = Pathname.new(@config.params[:flashlog])
|
81
|
+
return unless (log && log.file?)
|
82
|
+
|
83
|
+
Thread.new(log) do |log|
|
84
|
+
flashlog_timestamp ||= log.mtime
|
85
|
+
|
86
|
+
log.open('r') do |f|
|
87
|
+
f.read
|
88
|
+
loop do
|
89
|
+
if log.mtime > flashlog_timestamp
|
90
|
+
f.rewind
|
91
|
+
text = f.read
|
92
|
+
if text.length == 0
|
93
|
+
f.rewind
|
94
|
+
text = f.read
|
95
|
+
end
|
96
|
+
logger.info("FLASHLOG\n" + text) unless text.strip.empty?
|
97
|
+
flashlog_timestamp = log.mtime
|
98
|
+
end
|
99
|
+
sleep 1
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def compile_success_proc
|
106
|
+
if @httpd
|
107
|
+
@httpd.reload!
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def start_server
|
112
|
+
require 'rascut/httpd'
|
113
|
+
@httpd = Httpd.new(self)
|
114
|
+
@httpd.start
|
115
|
+
end
|
116
|
+
|
117
|
+
def setting_signals
|
118
|
+
methods(true).each do |mname|
|
119
|
+
if m = mname.match(/^sig_(.+)$/)
|
120
|
+
begin
|
121
|
+
Signal.trap(m[1].upcase) { method(mname).call }
|
122
|
+
rescue ArgumentError
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def sig_int
|
129
|
+
logger.debug 'SIG_INT'
|
130
|
+
self.exit()
|
131
|
+
end
|
132
|
+
|
133
|
+
def sig_usr2
|
134
|
+
logger.debug 'SIG_USR2'
|
135
|
+
@wrapper.compile
|
136
|
+
end
|
137
|
+
|
138
|
+
def exit
|
139
|
+
logger.info 'exiting...'
|
140
|
+
begin
|
141
|
+
@wrapper.close
|
142
|
+
rescue Exception => e
|
143
|
+
logger.error e.inspect
|
144
|
+
end
|
145
|
+
Kernel::exit 1
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'rascut/logger'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Rascut
|
6
|
+
class Config
|
7
|
+
DEFAULT_CONFIG = {
|
8
|
+
:interval => 1,
|
9
|
+
:compile_config => nil,
|
10
|
+
:file_observing => true,
|
11
|
+
:fcsh_cmd => 'fcsh',
|
12
|
+
:ext => ['as', 'css', 'mxml'],
|
13
|
+
:logger => Rascut::Logger.new(STDOUT),
|
14
|
+
}
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@params = DEFAULT_CONFIG.dup
|
18
|
+
@params[:logger].level = ::Logger::INFO
|
19
|
+
end
|
20
|
+
attr_accessor :params
|
21
|
+
|
22
|
+
def [](name)
|
23
|
+
@params[name]
|
24
|
+
end
|
25
|
+
|
26
|
+
def logger
|
27
|
+
@params[:logger]
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_argv!(argv)
|
31
|
+
op = OptionParser.new
|
32
|
+
op.banner = 'Usage: $ rascut HelloWrold.as'
|
33
|
+
|
34
|
+
#op.on('-a', 'Apollo compile mode') do |v|
|
35
|
+
# @params[:apollo] = true
|
36
|
+
# @params[:compile_config] = '+configname=apollo'
|
37
|
+
#end
|
38
|
+
|
39
|
+
op.on('-b=VAL', '--bind-address=VAL', 'server bind address(default 0.0.0.0)') {|v| @params[:bind_address] = v }
|
40
|
+
op.on('--compile-config=VAL', '-c=VAL', 'mxmlc compile config ex:) --compile-config="-benchmark -strict=true"') do |v|
|
41
|
+
if @params[:compile_config]
|
42
|
+
@params[:compile_config] << ' ' << v
|
43
|
+
else
|
44
|
+
@params[:compile_config] = v
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
op.on('--fcsh-cmd=VAL', 'fcsh command path') {|v| @params[:fcsh_cmd] = v }
|
49
|
+
@params[:observe_files] = []
|
50
|
+
op.on('-I=VAL', '--observe-files=VAL', 'observe files and directories path') {|v| @params[:observe_files] << v }
|
51
|
+
|
52
|
+
if @params[:observe_files].empty?
|
53
|
+
@params[:observe_files] << '.'
|
54
|
+
end
|
55
|
+
|
56
|
+
op.on('-i=VAL', '--interval=VAL', 'interval time(min)') {|v| @params[:interval] = v.to_i }
|
57
|
+
op.on('-l=VAL', '--log=VAL', 'showing flashlog.txt') {|v| @params[:flashlog] = v }
|
58
|
+
op.on('-m=VAL', '--mapping=VAL', 'server mapping path :example) -m "../assets=assets" -m "../images/=img"') {|v|
|
59
|
+
@params[:mapping] ||= []
|
60
|
+
@params[:mapping] << v.split('=', 2)
|
61
|
+
}
|
62
|
+
op.on('--no-file-observe', "don't observing files") {|v| @params[:file_observing] = false }
|
63
|
+
op.on('--observe-ext=VAL', 'observe ext ex:) --observe-ext="as3,actionscript3,css,mxml"') {|v| @params[:ext] = v.split(',') }
|
64
|
+
op.on('--server', '-s', 'start autoreload webserver') {|v| @params[:server] = true }
|
65
|
+
op.on('--server-handler=val', 'set server hander :example) --server-handler=webrick') {|v| @params[:server] = v }
|
66
|
+
op.on('--port=val', '-p=val', 'server port(default: 3001)') {|v| @params[:port] = v.to_i }
|
67
|
+
op.on('--plugin=VAL', 'load plugin(s)') {|v|
|
68
|
+
@params[:plugin] ||= []
|
69
|
+
@params[:plugin] << v
|
70
|
+
}
|
71
|
+
op.on('-t=VAL', '--template=VAL', 'server use template file') {|v| @params[:template] = v }
|
72
|
+
op.on('-v', '--verbose', 'detail messages') {|v| @params[:logger].level = Logger::DEBUG }
|
73
|
+
op.on('--help', 'show this message') { puts op; Kernel::exit 1 }
|
74
|
+
op.parse! argv
|
75
|
+
@params[:logger].debug 'config' + @params.inspect
|
76
|
+
end
|
77
|
+
|
78
|
+
def merge_config(file)
|
79
|
+
@params.merge! YAML.load_file(file)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
begin
|
2
|
+
require 'expect'
|
3
|
+
rescue LoadError
|
4
|
+
require 'pathname'
|
5
|
+
require Pathname.new(__FILE__).parent.parent.parent.join('vendor/ruby/expect')
|
6
|
+
end
|
7
|
+
require 'thread'
|
8
|
+
require 'rascut/file_observer'
|
9
|
+
|
10
|
+
module Rascut
|
11
|
+
class FcshWrapper
|
12
|
+
FCSH_RESULT_RE = /fcsh: Assigned (\d+) as the compile target id/
|
13
|
+
FCSH_WAIT_RE = /^\(fcsh\)\s*$/
|
14
|
+
|
15
|
+
attr_accessor :original_files, :files, :config, :target_script, :hooks
|
16
|
+
def initialize(target_script, config)
|
17
|
+
@target_script = target_script
|
18
|
+
@config = config
|
19
|
+
@hooks = Hash.new {|h, k| h[k] = []}
|
20
|
+
@mutex = Mutex.new
|
21
|
+
@compile_mutex = Mutex.new
|
22
|
+
@compile_id = nil
|
23
|
+
@process = nil
|
24
|
+
@not_first_read = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def reload!
|
28
|
+
if @compile_id
|
29
|
+
process_sync_exec("clear #{@compile_id}")
|
30
|
+
@compile_id = nil
|
31
|
+
end
|
32
|
+
call_hook :reload, @compile_id
|
33
|
+
end
|
34
|
+
|
35
|
+
def process_sync_exec(str, result_get = true)
|
36
|
+
res = nil
|
37
|
+
@mutex.synchronize do
|
38
|
+
@process.puts str
|
39
|
+
res = read_result(@process) if result_get
|
40
|
+
end
|
41
|
+
res
|
42
|
+
end
|
43
|
+
|
44
|
+
def close
|
45
|
+
if @process
|
46
|
+
@process.close
|
47
|
+
call_hook :close
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def logger
|
52
|
+
@config[:logger]
|
53
|
+
end
|
54
|
+
|
55
|
+
def mxmlc_cmd
|
56
|
+
cmd = ['mxmlc', @config[:compile_config], @target_script].join(' ')
|
57
|
+
logger.debug cmd
|
58
|
+
cmd
|
59
|
+
end
|
60
|
+
|
61
|
+
def compile
|
62
|
+
return false if @compile_mutex.locked?
|
63
|
+
|
64
|
+
@compile_mutex.synchronize do
|
65
|
+
logger.info "Compile Start"
|
66
|
+
out = nil
|
67
|
+
@process = IO.popen(@config[:fcsh_cmd] + ' 2>&1', 'r+') unless @process
|
68
|
+
if @compile_id
|
69
|
+
out = process_sync_exec "compile #{@compile_id}"
|
70
|
+
else
|
71
|
+
out = process_sync_exec mxmlc_cmd
|
72
|
+
if m = out.match(FCSH_RESULT_RE)
|
73
|
+
@compile_id = m[1]
|
74
|
+
else
|
75
|
+
raise "Can't get Compile ID\n" + out.to_s
|
76
|
+
end
|
77
|
+
end
|
78
|
+
logger.info out
|
79
|
+
if out.match(/bytes\)/)
|
80
|
+
call_hook :compile_success, out
|
81
|
+
else
|
82
|
+
call_hook :compile_error, out
|
83
|
+
end
|
84
|
+
call_hook :compile, out
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def call_hook(name, *args)
|
89
|
+
@hooks[name].each do |hook|
|
90
|
+
if hook.arity == 0 || args.length == 0
|
91
|
+
hook.call
|
92
|
+
else
|
93
|
+
hook.call(*args)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def read_result(process)
|
99
|
+
unless @not_first_read
|
100
|
+
# first_time, FIXME uncool...
|
101
|
+
process.expect(FCSH_WAIT_RE)
|
102
|
+
@not_first_read = true
|
103
|
+
end
|
104
|
+
|
105
|
+
process.expect(FCSH_WAIT_RE).first.sub(FCSH_WAIT_RE, '')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'find'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Rascut
|
6
|
+
class FileObserver
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
:interval => 1,
|
9
|
+
:ignore_files => [],
|
10
|
+
:ignore_dirs => [/\/.svn/],
|
11
|
+
:logger => Logger.new(STDOUT),
|
12
|
+
:dir_counter => 5,
|
13
|
+
:ext => nil
|
14
|
+
}
|
15
|
+
|
16
|
+
def initialize(files, options)
|
17
|
+
@files = {}
|
18
|
+
@dirs = {}
|
19
|
+
@options = DEFAULT_OPTIONS.merge options
|
20
|
+
@update_handlers = []
|
21
|
+
@th = nil
|
22
|
+
|
23
|
+
if options[:update_handler]
|
24
|
+
add_update_handler options.delete(:update_handler)
|
25
|
+
end
|
26
|
+
|
27
|
+
observe files
|
28
|
+
end
|
29
|
+
attr_accessor :options
|
30
|
+
|
31
|
+
def logger
|
32
|
+
options[:logger]
|
33
|
+
end
|
34
|
+
|
35
|
+
def run
|
36
|
+
if @th
|
37
|
+
@th.run
|
38
|
+
else
|
39
|
+
@th = Thread.start do
|
40
|
+
loop do
|
41
|
+
update_check
|
42
|
+
sleep @options[:interval]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def add_update_handler(handler)
|
49
|
+
unless @update_handlers.include? handler
|
50
|
+
@update_handlers << handler
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove_update_handler(handler)
|
55
|
+
@update_handlers.delete_if {|h| h == handler}
|
56
|
+
end
|
57
|
+
|
58
|
+
def stop
|
59
|
+
@th.kill
|
60
|
+
end
|
61
|
+
|
62
|
+
def observe(files)
|
63
|
+
Array(files).each do |file|
|
64
|
+
file = Pathname.new(file)
|
65
|
+
if file.directory?
|
66
|
+
dir_observe file
|
67
|
+
else
|
68
|
+
next if @options[:ignore_files].include?(file.realpath)
|
69
|
+
|
70
|
+
file_observe file
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def update_check
|
78
|
+
update_files = []
|
79
|
+
check_dirs if check_dir?
|
80
|
+
|
81
|
+
@files.each do |file, mtime|
|
82
|
+
if !file.readable?
|
83
|
+
@files.delete file
|
84
|
+
elsif file.mtime > mtime
|
85
|
+
@files[file] = file.mtime
|
86
|
+
update_files << file
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
unless update_files.empty?
|
91
|
+
logger.info 'Found update file(s)' + update_files.map{|f| f.to_s}.inspect
|
92
|
+
@update_handlers.each do |handler|
|
93
|
+
if handler.arity == 1
|
94
|
+
handler.call update_files
|
95
|
+
else
|
96
|
+
handler.call
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def check_dir?
|
103
|
+
@check_dir_count ||= options[:dir_counter]
|
104
|
+
if @check_dir_count > options[:dir_counter]
|
105
|
+
@check_dir_count = 0
|
106
|
+
else
|
107
|
+
@check_dir_count += 1
|
108
|
+
end
|
109
|
+
@check_dir_count.zero?
|
110
|
+
end
|
111
|
+
|
112
|
+
def check_dirs
|
113
|
+
dfiles = []
|
114
|
+
@dirs.each do |dir, mtime|
|
115
|
+
next if @options[:ignore_dirs].include?(dir.realpath)
|
116
|
+
|
117
|
+
if !dir.directory?
|
118
|
+
@dirs.delete dir
|
119
|
+
elsif dir.to_s.match %r{/\.svn|/CVS}
|
120
|
+
@dirs.delete dir
|
121
|
+
elsif dir.mtime > mtime
|
122
|
+
@dirs[dir] = dir.mtime
|
123
|
+
|
124
|
+
if @options[:ext]
|
125
|
+
e = '.{' + @options[:ext].join(',') + '}'
|
126
|
+
else
|
127
|
+
e = ''
|
128
|
+
end
|
129
|
+
dfiles.concat Pathname.glob(dir.to_s + "/{**/*}#{e}")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
dfiles.uniq.each do |file|
|
133
|
+
if file.directory?
|
134
|
+
dir_observe file
|
135
|
+
else
|
136
|
+
file_observe file, Time.at(0)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def file_observe(file, mtime = nil)
|
142
|
+
if @options[:ext]
|
143
|
+
if @options[:ext].include? file.extname.sub(/^\./, '')
|
144
|
+
@files[file] ||= (mtime || file.mtime)
|
145
|
+
end
|
146
|
+
else
|
147
|
+
@files[file] ||= (mtime || file.mtime)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def dir_observe(dir)
|
152
|
+
Find::find(dir.to_s) do |file|
|
153
|
+
if File.directory?(file)
|
154
|
+
dir = Pathname.new(file)
|
155
|
+
@dirs[dir] ||= dir.mtime
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
data/lib/rascut/httpd.rb
ADDED
@@ -0,0 +1,304 @@
|
|
1
|
+
|
2
|
+
begin
|
3
|
+
require 'rack'
|
4
|
+
rescue LoadError
|
5
|
+
require 'rubygems'
|
6
|
+
gem 'rack'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rack/showexceptions'
|
10
|
+
require 'rack/urlmap'
|
11
|
+
require 'rack/file'
|
12
|
+
require 'rack/request'
|
13
|
+
require 'rack/response'
|
14
|
+
require 'thread'
|
15
|
+
require 'logger'
|
16
|
+
require 'pathname'
|
17
|
+
require 'open-uri'
|
18
|
+
|
19
|
+
module Rascut
|
20
|
+
class Httpd
|
21
|
+
class FileOnly < Rack::File
|
22
|
+
def _call(env)
|
23
|
+
if env["PATH_INFO"].include? ".."
|
24
|
+
return [403, {"Content-Type" => "text/plain"}, ["Forbidden\n"]]
|
25
|
+
end
|
26
|
+
|
27
|
+
@path = env["PATH_INFO"] == '/' ? @root : F.join(@root, env['PATH_INFO'])
|
28
|
+
ext = F.extname(@path)[1..-1]
|
29
|
+
|
30
|
+
if F.file?(@path) && F.readable?(@path)
|
31
|
+
[200, {
|
32
|
+
"Content-Type" => MIME_TYPES[ext] || "text/plain",
|
33
|
+
"Content-Length" => F.size(@path).to_s
|
34
|
+
}, self]
|
35
|
+
else
|
36
|
+
return [404, {"Content-Type" => "text/plain"},
|
37
|
+
["File not found: #{env["PATH_INFO"]}\n"]]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(command)
|
43
|
+
@command = command
|
44
|
+
@threads = []
|
45
|
+
end
|
46
|
+
attr_reader :command
|
47
|
+
|
48
|
+
def start
|
49
|
+
swf_path = command.root.to_s
|
50
|
+
logger.debug "swf_path: #{swf_path}"
|
51
|
+
vendor = Pathname.new(__FILE__).parent.parent.parent.join('vendor')
|
52
|
+
logger.debug "vendor_path: #{vendor}"
|
53
|
+
reload = reload_handler
|
54
|
+
index = index_handler
|
55
|
+
|
56
|
+
#app = Rack::FixedBuilder.new do
|
57
|
+
# use Rack::ShowExceptions
|
58
|
+
# map('/reload') { run reload }
|
59
|
+
# map('/swf/') { run Rack::File.new(swf_path) }
|
60
|
+
# map('/') { run index }
|
61
|
+
#end
|
62
|
+
|
63
|
+
urls = []
|
64
|
+
urls.concat(config_url_mapping) if config[:mapping]
|
65
|
+
|
66
|
+
urls.concat([
|
67
|
+
['/js/swfobject.js', Rack::ShowExceptions.new(Httpd::FileOnly.new(vendor.join('js/swfobject.js').to_s))],
|
68
|
+
['/swf', Rack::ShowExceptions.new(Rack::File.new(swf_path))],
|
69
|
+
['/reload', Rack::ShowExceptions.new(reload_handler)],
|
70
|
+
['/proxy', Rack::ShowExceptions.new(proxy_handler)],
|
71
|
+
['/', Rack::ShowExceptions.new(index_handler)]
|
72
|
+
])
|
73
|
+
logger.debug 'url mappings: ' + urls.map{|u| u.first}.inspect
|
74
|
+
app = Rack::URLMap.new(urls)
|
75
|
+
port = config[:port] || 3001
|
76
|
+
host = config[:bind_address] || '0.0.0.0'
|
77
|
+
|
78
|
+
_args = [app, {:Host => host, :Port => port}]
|
79
|
+
server_handler = detect_server
|
80
|
+
Thread.new(_args) do |args|
|
81
|
+
server_handler.run *args
|
82
|
+
end
|
83
|
+
logger.info "Start #{server_handler} http://#{host}:#{port}/"
|
84
|
+
end
|
85
|
+
|
86
|
+
def config
|
87
|
+
command.config
|
88
|
+
end
|
89
|
+
|
90
|
+
def logger
|
91
|
+
config.logger
|
92
|
+
end
|
93
|
+
|
94
|
+
def reload!
|
95
|
+
while t = @threads.pop
|
96
|
+
t.run
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
def config_url_mapping
|
102
|
+
urls = []
|
103
|
+
config[:mapping].each do |m|
|
104
|
+
filepath = m[0]
|
105
|
+
mappath = m[1]
|
106
|
+
mappath = '/' + mappath if mappath[0..0] != '/'
|
107
|
+
urls << [mappath, Rack::ShowExceptions.new(Rack::File.new(command.root.join(filepath).to_s))]
|
108
|
+
end
|
109
|
+
urls
|
110
|
+
end
|
111
|
+
|
112
|
+
def detect_server
|
113
|
+
begin
|
114
|
+
case config[:server]
|
115
|
+
when 'mongrel'
|
116
|
+
require_mongrel_handler
|
117
|
+
when 'webrick'
|
118
|
+
require_webrick_handler
|
119
|
+
else
|
120
|
+
require_mongrel_handler
|
121
|
+
end
|
122
|
+
rescue Exception => e
|
123
|
+
require_webrick_handler
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def require_mongrel_handler
|
128
|
+
begin
|
129
|
+
require 'mongrel'
|
130
|
+
rescue LoadError
|
131
|
+
require 'rubygems'
|
132
|
+
gem 'mongrel', '> 1.0'
|
133
|
+
end
|
134
|
+
require 'rack/handler/mongrel'
|
135
|
+
Rack::Handler::Mongrel
|
136
|
+
end
|
137
|
+
|
138
|
+
def require_webrick_handler
|
139
|
+
require 'webrick'
|
140
|
+
require 'rack/handler/webrick'
|
141
|
+
Rack::Handler::WEBrick
|
142
|
+
end
|
143
|
+
|
144
|
+
def reload_handler
|
145
|
+
Proc.new do |env|
|
146
|
+
@threads << Thread.current
|
147
|
+
Thread.stop
|
148
|
+
|
149
|
+
logger.debug 'httpd /reload reloading now'
|
150
|
+
Rack::Response.new.finish do |r|
|
151
|
+
r.write '1'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def index_handler
|
157
|
+
if config[:template] && File.readable?(config[:template])
|
158
|
+
res = File.read(config[:template]) + "\n" + RELOAD_SCRIPT
|
159
|
+
else
|
160
|
+
res = INDEX.sub('__SWFOBJECT__', swftag(command.target_script, config)).sub('<!--__RELOAD__-->', RELOAD_SCRIPT)
|
161
|
+
end
|
162
|
+
|
163
|
+
Proc.new do |env|
|
164
|
+
req = Rack::Request.new(env)
|
165
|
+
res.sub!('__SWF_VARS__', swfvars(req.GET))
|
166
|
+
Rack::Response.new.finish do |r|
|
167
|
+
r.write res
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def proxy_handler
|
173
|
+
Proc.new do |env|
|
174
|
+
req = Rack::Request.new(env)
|
175
|
+
url = req.query_string
|
176
|
+
if url.empty?
|
177
|
+
url = req.path_info[1..-1].gsub(%r{^(https?:/)/?}, '\\1/')
|
178
|
+
end
|
179
|
+
Rack::Response.new.finish do |r|
|
180
|
+
open(url) { |io|
|
181
|
+
r['Content-Type'] = io.content_type
|
182
|
+
while part = io.read(8192)
|
183
|
+
r.write part
|
184
|
+
end
|
185
|
+
}
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def swfvars(vars)
|
191
|
+
res = []
|
192
|
+
vars.each do |key, value|
|
193
|
+
res << %Q[so.addVariable('#{key}', '#{value}');]
|
194
|
+
end
|
195
|
+
res.join("\n")
|
196
|
+
end
|
197
|
+
|
198
|
+
def swftag(target_script, options)
|
199
|
+
name = output_file(options[:compile_config]) || target_script
|
200
|
+
name = File.basename(name, '.*')
|
201
|
+
swf = "/swf/#{name}.swf"
|
202
|
+
height, width = wh_parse options[:compile_config]
|
203
|
+
bgcol = bg_parse options[:compile_config]
|
204
|
+
# %Q[new SWFObject("#{swf}?#{Time.now.to_i}#{Time.now.usec}", "#{name}", "#{width}", "#{height}", '9', '#{bgcol}');]
|
205
|
+
%Q[new SWFObject("#{swf}?" + (new Date()).getTime(), "idswf", "#{width}", "#{height}", '9', '#{bgcol}');]
|
206
|
+
end
|
207
|
+
|
208
|
+
def bg_parse(opt)
|
209
|
+
if m = opt.to_s.match(/-default-background-color=0x([a-fA-F0-9]{3,6})/)
|
210
|
+
'#' + m[1]
|
211
|
+
else
|
212
|
+
'#ffffff'
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def wh_parse(opt)
|
217
|
+
if m = opt.to_s.match(/-default-size\s+(\d+)\s+(\d+)/)
|
218
|
+
m.to_a[1..2]
|
219
|
+
else
|
220
|
+
['100%', '100%']
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def output_file(opt)
|
225
|
+
if m = opt.to_s.match(/-(o|output)\s+([^\s]+)/)
|
226
|
+
m[2]
|
227
|
+
else
|
228
|
+
nil
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
INDEX = <<-EOF
|
233
|
+
<html>
|
234
|
+
<head>
|
235
|
+
<title>Rascut</title>
|
236
|
+
<style>
|
237
|
+
* {
|
238
|
+
margin:0;
|
239
|
+
padding:0;
|
240
|
+
}
|
241
|
+
#content {
|
242
|
+
text-align:center;
|
243
|
+
}
|
244
|
+
</style>
|
245
|
+
<script type="text/javascript" src="/js/swfobject.js"></script>
|
246
|
+
<!--__RELOAD__-->
|
247
|
+
</head>
|
248
|
+
<body>
|
249
|
+
<div id="content">
|
250
|
+
</div>
|
251
|
+
|
252
|
+
<script type="text/javascript">
|
253
|
+
var so = __SWFOBJECT__;
|
254
|
+
__SWF_VARS__
|
255
|
+
so.addVariable('rascut', 'true');
|
256
|
+
so.write("content");
|
257
|
+
</script>
|
258
|
+
</body>
|
259
|
+
</html>
|
260
|
+
EOF
|
261
|
+
|
262
|
+
RELOAD_SCRIPT = <<-EOF
|
263
|
+
<script type="text/javascript">
|
264
|
+
var Rascut = new Object;
|
265
|
+
|
266
|
+
Rascut.xhr = (function() {
|
267
|
+
if (typeof XMLHttpRequest != 'undefined') {
|
268
|
+
return new XMLHttpRequest();
|
269
|
+
} else {
|
270
|
+
try {
|
271
|
+
return new ActiveXObject("Msxml2.XMLHTTP");
|
272
|
+
} catch(e) {
|
273
|
+
return new ActiveXObject("Microsoft.XMLHTTP");
|
274
|
+
}
|
275
|
+
}
|
276
|
+
})();
|
277
|
+
|
278
|
+
Rascut.reloadObserver = function() {
|
279
|
+
var x = Rascut.xhr;
|
280
|
+
x.open('GET', '/reload?' + (new Date()).getTime(), true);
|
281
|
+
x.onreadystatechange = function() {
|
282
|
+
try {
|
283
|
+
if (x.readyState == 4) {
|
284
|
+
if (x.status == 200 && Number(x.responseText) == 1) {
|
285
|
+
// thanks os0x!
|
286
|
+
so.attributes.swf = so.attributes.swf + '+';
|
287
|
+
so.write('content');
|
288
|
+
Rascut.reloadObserver();
|
289
|
+
} else {
|
290
|
+
setTimeout(Rascut.reloadObserver, 5000);
|
291
|
+
}
|
292
|
+
}
|
293
|
+
} catch(e) {
|
294
|
+
setTimeout(Rascut.reloadObserver, 5000);
|
295
|
+
}
|
296
|
+
}
|
297
|
+
x.send(null);
|
298
|
+
}
|
299
|
+
|
300
|
+
Rascut.reloadObserver();
|
301
|
+
</script>
|
302
|
+
EOF
|
303
|
+
end
|
304
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Rascut
|
4
|
+
class Logger < ::Logger
|
5
|
+
# This code from ActiveSupport
|
6
|
+
private
|
7
|
+
alias old_format_message format_message
|
8
|
+
if method_defined?(:formatter=)
|
9
|
+
def format_message(severity, timestamp, progname, msg)
|
10
|
+
"[#{Time.now.strftime('%m/%d %H:%M:%S')}] #{msg}\n"
|
11
|
+
end
|
12
|
+
else
|
13
|
+
def format_message(severity, timestamp, msg, progname)
|
14
|
+
"[#{Time.now.strftime('%m/%d %H:%M:%S')}] #{msg}\n"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
require 'rascut/plugin/base'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module Rascut
|
6
|
+
module Plugin
|
7
|
+
class WriteFcshErrorOutput < Base
|
8
|
+
def run
|
9
|
+
file = config[:filename] || Pathname.new(ENV['HOME']).join('.rascut/error_output')
|
10
|
+
@path = Pathname.new(file.to_s)
|
11
|
+
|
12
|
+
@command.wrapper.hooks[:compile_error] << method(:write_error_output)
|
13
|
+
@command.wrapper.hooks[:compile_success] << method(:write_error_none)
|
14
|
+
end
|
15
|
+
|
16
|
+
def write_error_output(str)
|
17
|
+
str.each_line do |line|
|
18
|
+
if line.match 'Error: '
|
19
|
+
@path.open('w'){|f| f.puts line.chomp }
|
20
|
+
break
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def write_error_none(str)
|
26
|
+
@path.open('w'){|f| f.write '' }
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/rascut.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../lib")
|
3
|
+
require 'rascut/file_observer'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'tmpdir'
|
6
|
+
require 'pathname'
|
7
|
+
$DEBUG = true
|
8
|
+
|
9
|
+
class FileObserverTest < Test::Unit::TestCase
|
10
|
+
def setup
|
11
|
+
@tmpdir = Pathname.new(Dir.tmpdir).join('test_file_observer_' + Time.now.to_i.to_s)
|
12
|
+
@tmpdir.mkpath
|
13
|
+
|
14
|
+
@fo = Rascut::FileObserver.new(@tmpdir.to_s, :interval => 1, :dir_counter => 0)
|
15
|
+
@update_files = []
|
16
|
+
|
17
|
+
@fo.add_update_handler method(:save_files)
|
18
|
+
|
19
|
+
@call_update_handler_flag = false
|
20
|
+
@fo.add_update_handler method(:call_update_handler)
|
21
|
+
|
22
|
+
@fo.run
|
23
|
+
end
|
24
|
+
|
25
|
+
def call_update_handler(files)
|
26
|
+
@call_update_handler_flag = true
|
27
|
+
end
|
28
|
+
|
29
|
+
def save_files(files)
|
30
|
+
@update_files << files
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_dir
|
34
|
+
sleep 1.1
|
35
|
+
@tmpdir.join('foo').mkpath
|
36
|
+
sleep 1.1
|
37
|
+
assert !@call_update_handler_flag
|
38
|
+
|
39
|
+
@tmpdir.join('foo/foo.txt').open('w') {|f| f.puts 'file'}
|
40
|
+
sleep 1.1
|
41
|
+
assert @call_update_handler_flag
|
42
|
+
@call_update_handler_flag = false
|
43
|
+
|
44
|
+
@tmpdir.join('foo/foo').mkpath
|
45
|
+
sleep 1.1
|
46
|
+
assert !@call_update_handler_flag
|
47
|
+
|
48
|
+
@tmpdir.join('foo/foo/foo.txt').open('w') {|f| f.puts 'file'}
|
49
|
+
sleep 1.1
|
50
|
+
assert @call_update_handler_flag
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_fileput
|
54
|
+
sleep 1
|
55
|
+
@tmpdir.join('foo.txt').open('w') {|f| f.puts 'file'}
|
56
|
+
sleep 1
|
57
|
+
assert @call_update_handler_flag
|
58
|
+
|
59
|
+
@call_update_handler_flag = false
|
60
|
+
sleep 1
|
61
|
+
@tmpdir.join('foo.txt').open('w+') {|f| f.puts 'file'}
|
62
|
+
sleep 1
|
63
|
+
assert @call_update_handler_flag
|
64
|
+
|
65
|
+
@call_update_handler_flag = false
|
66
|
+
sleep 1
|
67
|
+
assert(!@call_update_handler_flag)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_fileput_with_ext
|
71
|
+
@fo.options[:ext] = ['txt']
|
72
|
+
sleep 1
|
73
|
+
@tmpdir.join('foo.txt').open('w') {|f| f.puts 'file'}
|
74
|
+
sleep 1
|
75
|
+
assert @call_update_handler_flag
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_fileput_with_ext_nomatch
|
79
|
+
@fo.options[:ext] = ['nontext']
|
80
|
+
sleep 1
|
81
|
+
@tmpdir.join('foo.txt').open('w') {|f| f.puts 'file'}
|
82
|
+
sleep 1
|
83
|
+
assert !@call_update_handler_flag
|
84
|
+
end
|
85
|
+
|
86
|
+
def teardown
|
87
|
+
@fo.stop
|
88
|
+
@tmpdir.rmtree
|
89
|
+
end
|
90
|
+
end
|
data/test/test_rascut.rb
ADDED
File without changes
|
@@ -0,0 +1,8 @@
|
|
1
|
+
/**
|
2
|
+
* SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/
|
3
|
+
*
|
4
|
+
* SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License:
|
5
|
+
* http://www.opensource.org/licenses/mit-license.php
|
6
|
+
*
|
7
|
+
*/
|
8
|
+
if(typeof deconcept=="undefined"){var deconcept=new Object();}if(typeof deconcept.util=="undefined"){deconcept.util=new Object();}if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil=new Object();}deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a){if(!document.getElementById){return;}this.DETECT_KEY=_a?_a:"detectflash";this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY);this.params=new Object();this.variables=new Object();this.attributes=new Array();if(_1){this.setAttribute("swf",_1);}if(id){this.setAttribute("id",id);}if(w){this.setAttribute("width",w);}if(h){this.setAttribute("height",h);}if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));}this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion();if(!window.opera&&document.all&&this.installedVer.major>7){deconcept.SWFObject.doPrepUnload=true;}if(c){this.addParam("bgcolor",c);}var q=_7?_7:"high";this.addParam("quality",q);this.setAttribute("useExpressInstall",false);this.setAttribute("doExpressInstall",false);var _c=(_8)?_8:window.location;this.setAttribute("xiRedirectUrl",_c);this.setAttribute("redirectUrl","");if(_9){this.setAttribute("redirectUrl",_9);}};deconcept.SWFObject.prototype={useExpressInstall:function(_d){this.xiSWFPath=!_d?"expressinstall.swf":_d;this.setAttribute("useExpressInstall",true);},setAttribute:function(_e,_f){this.attributes[_e]=_f;},getAttribute:function(_10){return this.attributes[_10];},addParam:function(_11,_12){this.params[_11]=_12;},getParams:function(){return this.params;},addVariable:function(_13,_14){this.variables[_13]=_14;},getVariable:function(_15){return this.variables[_15];},getVariables:function(){return this.variables;},getVariablePairs:function(){var _16=new Array();var key;var _18=this.getVariables();for(key in _18){_16[_16.length]=key+"="+_18[key];}return _16;},getSWFHTML:function(){var _19="";if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","PlugIn");this.setAttribute("swf",this.xiSWFPath);}_19="<embed type=\"application/x-shockwave-flash\" src=\""+this.getAttribute("swf")+"\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\" style=\""+this.getAttribute("style")+"\"";_19+=" id=\""+this.getAttribute("id")+"\" name=\""+this.getAttribute("id")+"\" ";var _1a=this.getParams();for(var key in _1a){_19+=[key]+"=\""+_1a[key]+"\" ";}var _1c=this.getVariablePairs().join("&");if(_1c.length>0){_19+="flashvars=\""+_1c+"\"";}_19+="/>";}else{if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");this.setAttribute("swf",this.xiSWFPath);}_19="<object id=\""+this.getAttribute("id")+"\" classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\" style=\""+this.getAttribute("style")+"\">";_19+="<param name=\"movie\" value=\""+this.getAttribute("swf")+"\" />";var _1d=this.getParams();for(var key in _1d){_19+="<param name=\""+key+"\" value=\""+_1d[key]+"\" />";}var _1f=this.getVariablePairs().join("&");if(_1f.length>0){_19+="<param name=\"flashvars\" value=\""+_1f+"\" />";}_19+="</object>";}return _19;},write:function(_20){if(this.getAttribute("useExpressInstall")){var _21=new deconcept.PlayerVersion([6,0,65]);if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){this.setAttribute("doExpressInstall",true);this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl")));document.title=document.title.slice(0,47)+" - Flash Player Installation";this.addVariable("MMdoctitle",document.title);}}if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){var n=(typeof _20=="string")?document.getElementById(_20):_20;n.innerHTML=this.getSWFHTML();return true;}else{if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}}return false;}};deconcept.SWFObjectUtil.getPlayerVersion=function(){var _23=new deconcept.PlayerVersion([0,0,0]);if(navigator.plugins&&navigator.mimeTypes.length){var x=navigator.plugins["Shockwave Flash"];if(x&&x.description){_23=new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));}}else{if(navigator.userAgent&&navigator.userAgent.indexOf("Windows CE")>=0){var axo=1;var _26=3;while(axo){try{_26++;axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+_26);_23=new deconcept.PlayerVersion([_26,0,0]);}catch(e){axo=null;}}}else{try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");_23=new deconcept.PlayerVersion([6,0,21]);axo.AllowScriptAccess="always";}catch(e){if(_23.major==6){return _23;}}try{axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(e){}}if(axo!=null){_23=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}}}return _23;};deconcept.PlayerVersion=function(_29){this.major=_29[0]!=null?parseInt(_29[0]):0;this.minor=_29[1]!=null?parseInt(_29[1]):0;this.rev=_29[2]!=null?parseInt(_29[2]):0;};deconcept.PlayerVersion.prototype.versionIsValid=function(fv){if(this.major<fv.major){return false;}if(this.major>fv.major){return true;}if(this.minor<fv.minor){return false;}if(this.minor>fv.minor){return true;}if(this.rev<fv.rev){return false;}return true;};deconcept.util={getRequestParameter:function(_2b){var q=document.location.search||document.location.hash;if(_2b==null){return q;}if(q){var _2d=q.substring(1).split("&");for(var i=0;i<_2d.length;i++){if(_2d[i].substring(0,_2d[i].indexOf("="))==_2b){return _2d[i].substring((_2d[i].indexOf("=")+1));}}}return "";}};deconcept.SWFObjectUtil.cleanupSWFs=function(){var _2f=document.getElementsByTagName("OBJECT");for(var i=_2f.length-1;i>=0;i--){_2f[i].style.display="none";for(var x in _2f[i]){if(typeof _2f[i][x]=="function"){_2f[i][x]=function(){};}}}};if(deconcept.SWFObject.doPrepUnload){if(!deconcept.unloadSet){deconcept.SWFObjectUtil.prepUnload=function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};window.attachEvent("onunload",deconcept.SWFObjectUtil.cleanupSWFs);};window.attachEvent("onbeforeunload",deconcept.SWFObjectUtil.prepUnload);deconcept.unloadSet=true;}}if(!document.getElementById&&document.all){document.getElementById=function(id){return document.all[id];};}var getQueryParamValue=deconcept.util.getRequestParameter;var FlashObject=deconcept.SWFObject;var SWFObject=deconcept.SWFObject;
|
@@ -0,0 +1,36 @@
|
|
1
|
+
$expect_verbose = false
|
2
|
+
|
3
|
+
class IO
|
4
|
+
def expect(pat,timeout=9999999)
|
5
|
+
buf = ''
|
6
|
+
case pat
|
7
|
+
when String
|
8
|
+
e_pat = Regexp.new(Regexp.quote(pat))
|
9
|
+
when Regexp
|
10
|
+
e_pat = pat
|
11
|
+
end
|
12
|
+
while true
|
13
|
+
if IO.select([self],nil,nil,timeout).nil? then
|
14
|
+
result = nil
|
15
|
+
break
|
16
|
+
end
|
17
|
+
c = getc.chr
|
18
|
+
buf << c
|
19
|
+
if $expect_verbose
|
20
|
+
STDOUT.print c
|
21
|
+
STDOUT.flush
|
22
|
+
end
|
23
|
+
if mat=e_pat.match(buf) then
|
24
|
+
result = [buf,*mat.to_a[1..-1]]
|
25
|
+
break
|
26
|
+
end
|
27
|
+
end
|
28
|
+
if block_given? then
|
29
|
+
yield result
|
30
|
+
else
|
31
|
+
return result
|
32
|
+
end
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.1
|
3
|
+
specification_version: 1
|
4
|
+
name: rascut
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2007-09-02 00:00:00 +09:00
|
8
|
+
summary: Ruby ActionSCript UTility
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: hotchpotch@nononospam@gmail.com
|
12
|
+
homepage: " by Yuichi Tateno"
|
13
|
+
rubyforge_project: hotchpotch
|
14
|
+
description: "== FEATURES/PROBLEMS: == SYNOPSIS: * 1. flex2sdk and fcwrap setting. * 2. $ rascut -s MyScript.as * 3. Browser access http://localhost:3001/ == REQUIREMENTS:"
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- yuichi tateno
|
31
|
+
files:
|
32
|
+
- History.txt
|
33
|
+
- Manifest.txt
|
34
|
+
- README.txt
|
35
|
+
- Rakefile
|
36
|
+
- bin/rascut
|
37
|
+
- lib/rascut.rb
|
38
|
+
- lib/rascut/command.rb
|
39
|
+
- lib/rascut/config.rb
|
40
|
+
- lib/rascut/fcsh_wrapper.rb
|
41
|
+
- lib/rascut/file_observer.rb
|
42
|
+
- lib/rascut/httpd.rb
|
43
|
+
- lib/rascut/logger.rb
|
44
|
+
- lib/rascut/plugin/base.rb
|
45
|
+
- lib/rascut/plugin/write_fcsh_error_output.rb
|
46
|
+
- vendor/ruby/expect.rb
|
47
|
+
- vendor/js/swfobject.js
|
48
|
+
- test/test_rascut.rb
|
49
|
+
- test/test_file_observer.rb
|
50
|
+
test_files:
|
51
|
+
- test/test_rascut.rb
|
52
|
+
- test/test_file_observer.rb
|
53
|
+
rdoc_options:
|
54
|
+
- --main
|
55
|
+
- README.txt
|
56
|
+
extra_rdoc_files:
|
57
|
+
- History.txt
|
58
|
+
- Manifest.txt
|
59
|
+
- README.txt
|
60
|
+
executables:
|
61
|
+
- rascut
|
62
|
+
extensions: []
|
63
|
+
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
dependencies:
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: mongrel
|
69
|
+
version_requirement:
|
70
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 0.0.0
|
75
|
+
version:
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: rake
|
78
|
+
version_requirement:
|
79
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 0.0.0
|
84
|
+
version:
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: hoe
|
87
|
+
version_requirement:
|
88
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 0.0.0
|
93
|
+
version:
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rack
|
96
|
+
version_requirement:
|
97
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 0.0.0
|
102
|
+
version:
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: hoe
|
105
|
+
version_requirement:
|
106
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.3.0
|
111
|
+
version:
|