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.
@@ -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
+