sleipnir-api 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
- if tab.location.href =~ /workspace/
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
- * grepnir
6
- * example
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
-
@@ -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
+