rascut 0.1.0
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/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:
|