sleipnir-api 0.1.0 → 0.2.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 +13 -0
- data/Manifest.txt +7 -0
- data/README.txt +10 -4
- data/TODO.txt +21 -4
- data/bin/grepnir +91 -0
- data/examples/close_dup.rb +17 -0
- data/lib/sleipnir_api/cli/base.rb +77 -0
- data/lib/sleipnir_api/cli/grepnir.rb +188 -0
- data/lib/sleipnir_api/output.rb +2 -2
- data/lib/sleipnir_api/tab.rb +69 -9
- data/lib/sleipnir_api/util.rb +4 -0
- data/lib/sleipnir_api/version.rb +1 -1
- data/spec/dsl/behaviour_eval.rb +5 -0
- data/spec/matchers/exit_with.rb +35 -0
- data/spec/matchers/path_eql.rb +24 -26
- data/spec/sleipnir_api/cli/grepnir_spec.rb +341 -0
- data/spec/sleipnir_api/dialog_mock_spec.rb +1 -1
- data/spec/sleipnir_api/key_state_mock_spec.rb +1 -1
- data/spec/sleipnir_api/security_mock_spec.rb +1 -1
- data/spec/sleipnir_api/security_spec.rb +1 -1
- data/spec/sleipnir_api/sleipnir_spec.rb +20 -20
- data/spec/sleipnir_api/tab_mock_spec.rb +20 -2
- data/spec/sleipnir_api/tab_spec.rb +16 -3
- data/spec/spec_helper.rb +17 -0
- metadata +11 -4
data/History.txt
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
== 0.2.0 / 2007-07-29
|
2
|
+
|
3
|
+
* Added grepnir command to search Sleipnir tab.
|
4
|
+
* API changes:
|
5
|
+
* SleipnirAPI::Tab
|
6
|
+
+window+:: support block argument.
|
7
|
+
+document+:: ditto.
|
8
|
+
+browser+:: ditto.
|
9
|
+
+location+:: ditto.
|
10
|
+
+close+:: now take +force+ optional argument to close navigate locked tab.
|
11
|
+
+hilight+:: support multiple keywords.
|
12
|
+
+selection_text+:: add new method to get selected text.
|
13
|
+
|
1
14
|
== 0.1.0 / 2007-07-22
|
2
15
|
|
3
16
|
* Initial beta release
|
data/Manifest.txt
CHANGED
@@ -4,12 +4,16 @@ Manifest.txt
|
|
4
4
|
README.txt
|
5
5
|
Rakefile
|
6
6
|
TODO.txt
|
7
|
+
bin/grepnir
|
8
|
+
examples/close_dup.rb
|
7
9
|
examples/reload.rb
|
8
10
|
helper/helper.rb
|
9
11
|
helper/rake.rb
|
10
12
|
helper/rake_sh_filter.rb
|
11
13
|
helper/util.rb
|
12
14
|
lib/sleipnir_api.rb
|
15
|
+
lib/sleipnir_api/cli/base.rb
|
16
|
+
lib/sleipnir_api/cli/grepnir.rb
|
13
17
|
lib/sleipnir_api/dialog.rb
|
14
18
|
lib/sleipnir_api/key_state.rb
|
15
19
|
lib/sleipnir_api/output.rb
|
@@ -24,7 +28,10 @@ lib/sleipnir_api/version.rb
|
|
24
28
|
lib/sleipnir_api/win32api.rb
|
25
29
|
scripts/rdoc_filter.rb
|
26
30
|
setup.rb
|
31
|
+
spec/dsl/behaviour_eval.rb
|
32
|
+
spec/matchers/exit_with.rb
|
27
33
|
spec/matchers/path_eql.rb
|
34
|
+
spec/sleipnir_api/cli/grepnir_spec.rb
|
28
35
|
spec/sleipnir_api/dialog_mock_spec.rb
|
29
36
|
spec/sleipnir_api/key_state_mock_spec.rb
|
30
37
|
spec/sleipnir_api/output_spec.rb
|
data/README.txt
CHANGED
@@ -16,14 +16,19 @@ API 仕様は SleipnirAPI を参照してください。
|
|
16
16
|
require "sleipnir_api"
|
17
17
|
|
18
18
|
SleipnirAPI.new do |pnir|
|
19
|
-
pnir.each do |tab|
|
20
|
-
|
21
|
-
tab.location.reload
|
22
|
-
end
|
19
|
+
pnir.select{|tab| tab.location.href =~ /workspace/ }.each do |tab|
|
20
|
+
tab.location.reload
|
23
21
|
end
|
24
22
|
end
|
25
23
|
|
26
24
|
|
25
|
+
=== COMMAND
|
26
|
+
|
27
|
+
sleipnir-api は _grepnir_ コマンドが付属しています。
|
28
|
+
|
29
|
+
詳細は {grepnir}[link:files/bin/grepnir.html] を参照してください。
|
30
|
+
|
31
|
+
|
27
32
|
=== INSTALL
|
28
33
|
|
29
34
|
[Unix]
|
@@ -40,6 +45,7 @@ API 仕様は SleipnirAPI を参照してください。
|
|
40
45
|
|
41
46
|
* Sleipnir 2.xx でのテストはあまりしていません。
|
42
47
|
|
48
|
+
|
43
49
|
=== COPYRIGHT
|
44
50
|
|
45
51
|
Copyright (c) 2007 MIYAMUKO Katsuyuki.
|
data/TODO.txt
CHANGED
@@ -1,11 +1,28 @@
|
|
1
1
|
== TODO
|
2
2
|
|
3
|
+
* search, hilight を自前で実装する
|
4
|
+
* Sleipnir 2.x じゃサポートしていない
|
5
|
+
* 1.66 で hilight を同じページに対して何回も実行するとだんだん重くなる
|
6
|
+
* watir サポート
|
7
|
+
* InternetExplorer.Application 互換のインターフェイスを提供する
|
8
|
+
Adapter を作ってタブごとに watir オブジェクトを取得できればよい?
|
9
|
+
* InternetExplorer.Application == IWebBrowser2 == pnir.browser
|
10
|
+
* ie.document == DispHTMLDocument == pnir.document
|
11
|
+
* ie.parentWindow == DispHTMLWindow2 == pnir.window
|
12
|
+
* ipnir
|
13
|
+
* intaractive sleipnir shell
|
14
|
+
* JavaScript の実行
|
3
15
|
* Sleipnir の起動・終了を WMI を使わずに実装。
|
4
16
|
* Sleipnir の終了時に Window Handle をちゃんと見る。
|
5
|
-
*
|
6
|
-
*
|
17
|
+
* Sleipnir の IE コンポーネント部分の Window Handle の取得。
|
18
|
+
* Internet Explorer_Server
|
19
|
+
* ウィンドウの screen shot
|
20
|
+
* Sleipnir.API proxy interface
|
21
|
+
* JSON-RPC
|
22
|
+
* XML-RPC
|
23
|
+
* dRuby
|
24
|
+
* Rinda
|
25
|
+
* Gearman
|
7
26
|
* ExecCommand
|
8
27
|
* コマンドの一覧
|
9
28
|
* Sleipnir 2.x のサポート
|
10
|
-
* ExecAction とか
|
11
|
-
|
data/bin/grepnir
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# == NAME
|
5
|
+
#
|
6
|
+
# grepnir - Sleipnir で開いている Web ページを grep する
|
7
|
+
#
|
8
|
+
# == SYNOPSIS
|
9
|
+
#
|
10
|
+
# Usage: grepnir [OPTION]... PATTERN...
|
11
|
+
#
|
12
|
+
#
|
13
|
+
# == DESCRIPTION
|
14
|
+
#
|
15
|
+
# grepnir は Sleipnir で開いている Web ページの内容をキーワード検索するコマンドです。
|
16
|
+
#
|
17
|
+
# キーワードにマッチしたタブに対して以下のアクションを実行できます。
|
18
|
+
#
|
19
|
+
# * アクティブなタブにする (-A)
|
20
|
+
# * タイトルにスター (*) を付ける (-T)
|
21
|
+
# * ナビゲートロック (-L)
|
22
|
+
# * ハイライト (-H)
|
23
|
+
# * キーワードを選択 (-S)
|
24
|
+
# * ヒットした URL とタイトルを表示
|
25
|
+
#
|
26
|
+
# --include, --exclude, --only-locked-tab で特定の URL だけ検索することができます。
|
27
|
+
#
|
28
|
+
#
|
29
|
+
# == USAGE
|
30
|
+
#
|
31
|
+
# Usage: grepnir [OPTION]... PATTERN...
|
32
|
+
#
|
33
|
+
# Sleipnir control:
|
34
|
+
# -A, --[no-]activate activate 1st matched tab
|
35
|
+
# -T, --[no-]title-star add star '*' to title
|
36
|
+
# -L, --[no-]lock navigate lock for each matched tab
|
37
|
+
# -H, --[no-]hilight hilight to distinguish the matched text
|
38
|
+
# -S, --[no-]search search and select matched text
|
39
|
+
#
|
40
|
+
# Match control:
|
41
|
+
# -v, --invert-match select non-matching tabs
|
42
|
+
# -l, --only-locked-tab search navigate lock tabs only
|
43
|
+
# --include=PATTERN URLs that match PATTERN will be examined
|
44
|
+
# --exclude=PATTERN URLs that match PATTERN will be skipped
|
45
|
+
#
|
46
|
+
# Miscellaneous:
|
47
|
+
# -V, --version print version information and exit
|
48
|
+
# -h, --help print this help and exit
|
49
|
+
#
|
50
|
+
# Default options:
|
51
|
+
# -A -T -S
|
52
|
+
#
|
53
|
+
#
|
54
|
+
# == CAVEATS
|
55
|
+
#
|
56
|
+
# * Sleipnir 2.x ではハイライト (-H) と選択 (-S) はサポートしていないので、
|
57
|
+
# オプションを指定しても単純に無視します。
|
58
|
+
#
|
59
|
+
# * Sleipnir 1.x で同じページに対して何回もハイライト処理をすると
|
60
|
+
# 処理をするたびに重くなります。
|
61
|
+
#
|
62
|
+
#
|
63
|
+
# == EXIT STATUS
|
64
|
+
#
|
65
|
+
# 0:: 指定したパターンがマッチした場合
|
66
|
+
# 1:: 指定したパターンがマッチしなかった場合
|
67
|
+
# 2:: 引数が不正など何かエラーが起きた場合
|
68
|
+
#
|
69
|
+
|
70
|
+
module SleipnirAPI
|
71
|
+
class Launcher #:nodoc:
|
72
|
+
|
73
|
+
def self.production?
|
74
|
+
$LOADED_FEATURES.include?("rubygems.rb") and File.exist?(File.join(File.dirname($0), "ruby.exe"))
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.add_lib_to_load_path
|
78
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "../lib")
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.launch
|
82
|
+
add_lib_to_load_path unless production?
|
83
|
+
require "optparse"
|
84
|
+
require "sleipnir_api/cli/grepnir"
|
85
|
+
::SleipnirAPI::CLI::Grepnir.new.execute(ARGV)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
SleipnirAPI::Launcher.launch
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "../lib")
|
4
|
+
require "sleipnir_api"
|
5
|
+
|
6
|
+
SleipnirAPI.new do |pnir|
|
7
|
+
url2tab = pnir.to_set.classify{|e| e.document.URL }.select{|url,tabs| tabs.size > 1 }
|
8
|
+
url2tab.each do |url,tabs|
|
9
|
+
tabs.sort_by{|e|
|
10
|
+
[e.navigate_lock? ? 0 : 1,
|
11
|
+
e.active? ? 0 : 1,
|
12
|
+
e.read? ? 0 : 1,
|
13
|
+
e.busy? ? 1 : 0,
|
14
|
+
e.index]
|
15
|
+
}[1..-1].each{|e| e.close(true) }
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module SleipnirAPI
|
2
|
+
module CLI #:nodoc:
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
class SleipnirAPI::CLI::Base #:nodoc:
|
7
|
+
|
8
|
+
class SleipnirAPI::CLI::Exit < SystemExit #:nodoc:
|
9
|
+
attr_reader :status
|
10
|
+
def initialize(status)
|
11
|
+
@status = status
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(stdin = nil, stdout = nil, stderr = nil, exit_when_done = true)
|
16
|
+
@stdin = stdin
|
17
|
+
@stdout = stdout
|
18
|
+
@stderr = stderr
|
19
|
+
@exit_when_done = exit_when_done
|
20
|
+
end
|
21
|
+
|
22
|
+
def done!(status)
|
23
|
+
if @exit_when_done
|
24
|
+
exit status
|
25
|
+
else
|
26
|
+
raise SleipnirAPI::CLI::Exit, status
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def stdin
|
31
|
+
@stdin || $stdin
|
32
|
+
end
|
33
|
+
|
34
|
+
def stdout
|
35
|
+
@stdout || $stdout
|
36
|
+
end
|
37
|
+
|
38
|
+
def stderr
|
39
|
+
@stderr || $stderr
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize_context(ctx)
|
43
|
+
end
|
44
|
+
|
45
|
+
def process_arguments(ctx, args)
|
46
|
+
end
|
47
|
+
|
48
|
+
def prepare(args)
|
49
|
+
ctx = OpenStruct.new
|
50
|
+
initialize_context(ctx)
|
51
|
+
process_arguments(ctx, args)
|
52
|
+
ctx
|
53
|
+
end
|
54
|
+
|
55
|
+
def execute(args)
|
56
|
+
begin
|
57
|
+
execute0(args)
|
58
|
+
rescue SleipnirAPI::CLI::Exit => e
|
59
|
+
return e.status
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def execute0(args)
|
64
|
+
ctx = prepare(args)
|
65
|
+
|
66
|
+
begin
|
67
|
+
match = SleipnirAPI.connect do |pnir|
|
68
|
+
perform(ctx, pnir)
|
69
|
+
end
|
70
|
+
done!(match ? 0 : 1)
|
71
|
+
rescue SleipnirAPI::ConnectError => e
|
72
|
+
stderr.puts "Sleipnir does not running."
|
73
|
+
done!(2)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
|
3
|
+
require "sleipnir_api"
|
4
|
+
require "sleipnir_api/cli/base"
|
5
|
+
|
6
|
+
class SleipnirAPI::CLI::Grepnir < SleipnirAPI::CLI::Base #:nodoc:
|
7
|
+
|
8
|
+
class Action #:nodoc:
|
9
|
+
def initialize(cli)
|
10
|
+
@cli = cli
|
11
|
+
@actions = self.private_methods(false) - ["initialize"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(ctx, *args, &block)
|
15
|
+
@actions.each do |act|
|
16
|
+
next unless ctx.action.__send__(act)
|
17
|
+
self.__send__(act, ctx, *args, &block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def activate(ctx, pnir, tab, doc, text, matched)
|
24
|
+
return if ctx.scope.req[:activated]
|
25
|
+
if matched
|
26
|
+
tab.activate
|
27
|
+
ctx.scope.req[:activated] = true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def title_star(ctx, pnir, tab, doc, text, matched)
|
32
|
+
current = tab.document.Title
|
33
|
+
star = current.match(/\A\* /)
|
34
|
+
if matched
|
35
|
+
tab.document.Title = "* #{current}" unless star
|
36
|
+
else
|
37
|
+
tab.document.Title = current[2..-1] if star
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def lock(ctx, pnir, tab, doc, text, matched)
|
42
|
+
tab.navigate_lock = matched
|
43
|
+
end
|
44
|
+
|
45
|
+
def hilight(ctx, pnir, tab, doc, text, matched)
|
46
|
+
return if pnir.v2?
|
47
|
+
if ctx.invert_match or not matched
|
48
|
+
tab.hilight("")
|
49
|
+
else
|
50
|
+
tab.hilight(ctx.keywords)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def search(ctx, pnir, tab, doc, text, matched)
|
55
|
+
return if pnir.v2?
|
56
|
+
if ctx.invert_match or not matched
|
57
|
+
tab.document.Selection.Empty
|
58
|
+
else
|
59
|
+
ctx.keywords.each do |kwd|
|
60
|
+
break if tab.search(kwd)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def output(ctx, pnir, tab, doc, text, matched)
|
66
|
+
return unless matched
|
67
|
+
@cli.stdout.puts "- #{doc.Title}"
|
68
|
+
@cli.stdout.puts " #{doc.URL}"
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
DEFAULT_ARGUMENTS = %W(-A -T -S)
|
75
|
+
|
76
|
+
def initialize(*args)
|
77
|
+
super(*args)
|
78
|
+
@action = Action.new(self)
|
79
|
+
end
|
80
|
+
|
81
|
+
def initialize_context(ctx)
|
82
|
+
ctx.action = OpenStruct.new
|
83
|
+
ctx.flag = OpenStruct.new
|
84
|
+
ctx.scope = OpenStruct.new.instance_eval {
|
85
|
+
self.app = {}
|
86
|
+
self.req = {}
|
87
|
+
self.tab = {}
|
88
|
+
self
|
89
|
+
}
|
90
|
+
ctx.action.output = true
|
91
|
+
ctx.includes = []
|
92
|
+
ctx.excludes = []
|
93
|
+
end
|
94
|
+
|
95
|
+
def argument_processor(ctx)
|
96
|
+
Proc.new do |opt|
|
97
|
+
opt.banner = "Usage: grepnir [OPTION]... PATTERN..."
|
98
|
+
|
99
|
+
opt.separator ""
|
100
|
+
opt.separator " Sleipnir control:"
|
101
|
+
opt.on("-A", "--[no-]activate", "activate 1st matched tab") {|v|
|
102
|
+
ctx.action.activate = v }
|
103
|
+
opt.on("-T", "--[no-]title-star", "add star '*' to title") {|v|
|
104
|
+
ctx.action.title_star = v }
|
105
|
+
opt.on("-L", "--[no-]lock", "navigate lock for each matched tab") {|v|
|
106
|
+
ctx.action.lock = v }
|
107
|
+
opt.on("-H", "--[no-]hilight", "hilight to distinguish the matched text") {|v|
|
108
|
+
ctx.action.hilight = v }
|
109
|
+
opt.on("-S", "--[no-]search", "search and select matched text") {|v|
|
110
|
+
ctx.action.search = v }
|
111
|
+
|
112
|
+
opt.separator ""
|
113
|
+
opt.separator " Match control:"
|
114
|
+
opt.on("-v", "--invert-match", "select non-matching tabs") {
|
115
|
+
ctx.invert_match = true }
|
116
|
+
opt.on("-l", "--only-locked-tab", "search navigate lock tabs only") {|v|
|
117
|
+
ctx.only_locked_tab = true }
|
118
|
+
opt.on("--include=PATTERN", "URLs that match PATTERN will be examined") {|v|
|
119
|
+
ctx.includes << v }
|
120
|
+
opt.on("--exclude=PATTERN", "URLs that match PATTERN will be skipped") {|v|
|
121
|
+
ctx.excludes << v }
|
122
|
+
|
123
|
+
opt.separator ""
|
124
|
+
opt.separator " Miscellaneous:"
|
125
|
+
opt.on("-V", "--version", "print version information and exit") {
|
126
|
+
stdout.puts "grepnir #{SleipnirAPI::VERSION::STRING}"
|
127
|
+
done!(0)
|
128
|
+
}
|
129
|
+
opt.on("-h", "--help", "print this help and exit") {
|
130
|
+
stdout.puts opt
|
131
|
+
done!(0)
|
132
|
+
}
|
133
|
+
|
134
|
+
opt.separator ""
|
135
|
+
opt.separator " Default options:"
|
136
|
+
opt.separator " #{DEFAULT_ARGUMENTS * ' '}"
|
137
|
+
|
138
|
+
opt.parse!
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def target_tab?(ctx, tab)
|
143
|
+
return false if ctx.only_locked_tab and not tab.navigate_lock?
|
144
|
+
url = tab.document.URL
|
145
|
+
return false if ctx.exclude_re.match(url)
|
146
|
+
return true if ctx.includes.empty?
|
147
|
+
return true if ctx.include_re.match(url)
|
148
|
+
false
|
149
|
+
end
|
150
|
+
|
151
|
+
def process_arguments(ctx, args)
|
152
|
+
proc = argument_processor(ctx)
|
153
|
+
|
154
|
+
defaults = DEFAULT_ARGUMENTS.dup.extend(OptionParser::Arguable)
|
155
|
+
defaults.options(&proc)
|
156
|
+
|
157
|
+
args.options(&proc)
|
158
|
+
if args.empty?
|
159
|
+
stderr.puts "missing PATTERN"
|
160
|
+
stderr.puts args.options
|
161
|
+
done!(2)
|
162
|
+
end
|
163
|
+
|
164
|
+
ctx.keywords = args.dup
|
165
|
+
ctx.keyword_re = ctx.keywords.map{|e| /#{Regexp.quote(e)}/i }
|
166
|
+
|
167
|
+
ctx.include_re = Regexp.union(*ctx.includes)
|
168
|
+
ctx.exclude_re = Regexp.union(*ctx.excludes)
|
169
|
+
end
|
170
|
+
|
171
|
+
def perform(ctx, pnir)
|
172
|
+
r = false
|
173
|
+
ctx.scope.req.clear
|
174
|
+
pnir.select{|tab| target_tab?(ctx, tab) }.each do |tab|
|
175
|
+
ctx.scope.tab.clear
|
176
|
+
tab.document {|doc|
|
177
|
+
text = doc.body.innerText
|
178
|
+
matched = ctx.keyword_re.all?{|re| re.match(text) }
|
179
|
+
matched = !matched if ctx.invert_match
|
180
|
+
@action.run(ctx, pnir, tab, doc, text, matched)
|
181
|
+
r = true if matched
|
182
|
+
}
|
183
|
+
end
|
184
|
+
r
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|