sleipnir-api 0.2.1 → 0.3.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.
Files changed (41) hide show
  1. data/History.txt +32 -0
  2. data/Manifest.txt +20 -3
  3. data/Rakefile +11 -1
  4. data/TODO.txt +4 -10
  5. data/bin/grepnir +1 -1
  6. data/examples/close_dup.rb +1 -1
  7. data/examples/close_err.rb +12 -0
  8. data/examples/command_list.rb +135 -0
  9. data/examples/open_last_url_by_firefox.rb +44 -0
  10. data/examples/open_selected_links.rb +40 -0
  11. data/helper/rake.rb +3 -57
  12. data/helper/rake/rake.rb +58 -0
  13. data/helper/{rake_sh_filter.rb → rake/rake_sh_filter.rb} +0 -0
  14. data/helper/{util.rb → rake/util.rb} +0 -0
  15. data/lib/sleipnir_api/cli/grepnir.rb +2 -3
  16. data/lib/sleipnir_api/command.rb +126 -0
  17. data/lib/sleipnir_api/commands.rb +264 -0
  18. data/lib/sleipnir_api/profile.rb +166 -27
  19. data/lib/sleipnir_api/profile/ini.rb +202 -0
  20. data/lib/sleipnir_api/profile/key.rb +120 -0
  21. data/lib/sleipnir_api/profile/section.rb +147 -0
  22. data/lib/sleipnir_api/profile/util.rb +82 -0
  23. data/lib/sleipnir_api/searcher.rb +133 -0
  24. data/lib/sleipnir_api/security.rb +88 -18
  25. data/lib/sleipnir_api/sleipnir.rb +91 -7
  26. data/lib/sleipnir_api/tab.rb +68 -2
  27. data/lib/sleipnir_api/tabbed_ie.rb +33 -0
  28. data/lib/sleipnir_api/util.rb +25 -0
  29. data/lib/sleipnir_api/version.rb +2 -2
  30. data/scripts/gesture2rb.rb +42 -0
  31. data/scripts/make_gesture.rb +271 -0
  32. data/scripts/subcategory.csv +253 -0
  33. data/spec/sleipnir_api/profile_mock_spec.rb +80 -6
  34. data/spec/sleipnir_api/profile_section_mock_spec.rb +143 -0
  35. data/spec/sleipnir_api/profile_spec.rb +191 -0
  36. data/spec/sleipnir_api/security_spec.rb +58 -0
  37. data/spec/sleipnir_api/tab_mock_spec.rb +0 -5
  38. data/spec/sleipnir_api/tab_spec.rb +27 -0
  39. data/spec/spec_helper.rb +20 -0
  40. metadata +22 -5
  41. data/helper/helper.rb +0 -3
@@ -1,46 +1,150 @@
1
1
  require "sleipnir_api/util"
2
+ require "sleipnir_api/profile/ini"
3
+ require "sleipnir_api/profile/section"
4
+ require "sleipnir_api/profile/key"
2
5
 
3
6
  module SleipnirAPI
4
7
 
5
8
  #
6
9
  # このクラスは Sleipnir の COM オブジェクト (Sleipnir.API) の wrapper クラスです。
7
- # Sleipnir の ini ファイルを操作する API を定義しています。
10
+ # Sleipnir の ini ファイルを操作する低レベルな API を定義しています。
11
+ #
12
+ # ini ファイル・セクション・キーに対応するオブジェクトを用意してあるので
13
+ # 通常はそちらを利用してください。
14
+ #
15
+ # * SleipnirAPI::Profile::Ini
16
+ # * SleipnirAPI::Profile::Section
17
+ # * SleipnirAPI::Profile::Key
8
18
  #
9
19
  # このオブジェクトは SleipnirAPI::Sleipnir#profile で取得します。
10
20
  #
11
- # 例:
21
+ # === 高レベル API の例
22
+ #
23
+ # pnir = SleipnirAPI.new
24
+ # prof = pnir.profile
25
+ #
26
+ # # デフォルト値
27
+ # bar = prof.script.foo_section.bar_key
28
+ # # 以下と同じ
29
+ # # bar = prof.ini("Script.ini").section("foo_section").key("bar_key")
30
+ #
31
+ # bar.write_string("foobar")
32
+ # bar.get_string #=> "foobar"
33
+ # bar.delete
34
+ # bar.get_string(:default => "default value") #=> "default value"
35
+ #
36
+ # # 暗号化
37
+ # bar_cipher = prof.script.foo_section.bar_key(:cipher => true)
38
+ # bar_cipher.write_string("foobar")
39
+ # bar_cipher.get_string #=> "foobar"
40
+ # bar.get_string #=> "tibv&DmD[vq)"
41
+ # bar_cipher.get_string(:cipher => false) #=> "tibv&DmD[vq)"
42
+ #
43
+ # # 連番データの取得
44
+ # history = prof.History.History2.key("URL-data0").list("URLCount")
45
+ #
46
+ # === 低レベル API の例
12
47
  #
13
48
  # pnir = SleipnirAPI.new
14
- # ini = pnir.profile
49
+ # prof = pnir.profile
15
50
  #
16
51
  # # デフォルト値
17
- # ini.write_string("section", "key", "foobar")
18
- # ini.get_string("section", "key") #=> "foobar"
19
- # ini.delete("section", "key")
20
- # ini.get_string("section", "key", :default => "default value") #=> "default value"
52
+ # prof.write_string("section_foo", key_bar, "foobar")
53
+ # prof.get_string("section_foo", key_bar) #=> "foobar"
54
+ # prof.delete("section_foo", key_bar)
55
+ # prof.get_string("section_foo", key_bar, :default => "default value") #=> "default value"
21
56
  #
22
57
  # # 暗号化
23
- # ini.write_string("section", "key", "foobar", :cipher => true)
24
- # ini.get_string("section", "key") #=> "tF4DxDH)[uUu"
25
- # ini.get_string("section", "key", :cipher => true) #=> "foobar"
58
+ # prof.write_string("section_foo", key_bar, "foobar", :cipher => true)
59
+ # prof.get_string("section_foo", key_bar, :cipher => true) #=> "foobar"
60
+ # prof.get_string("section_foo", key_bar) #=> "tF4DxDH)[uUu"
26
61
  #
27
- # # ファイル名指定
28
- # count = ini.get_int("Proxy", "Count", :ini => "proxy.ini")
29
- # (0...count).each do |i|
30
- # p ini.get_string("Proxy", "Proxy#{i}_Title", :ini => "proxy.ini")
31
- # end
62
+ # # 連番データの取得
63
+ # history = prof.list("History2", "URL-data0", "URLCount", :ini => "History.ini")
32
64
  #
33
65
  class Profile
34
66
  include SleipnirAPI::Util
67
+ include OptionArgument
68
+ include DataUtil
35
69
 
36
70
  # SleipnirAPI::Sleipnir object
37
- attr_reader :sleipnir
71
+ attr_reader :sleipnir, :default_opts
38
72
 
39
- def initialize(sleipnir)
73
+ def initialize(sleipnir, default_opts = nil)
40
74
  @sleipnir = sleipnir
75
+ @user_path = sleipnir.user_path
76
+ @default_opts = default_opts
41
77
  end
42
78
 
79
+
80
+ # call-seq:
81
+ # list(section, keyfmt, countkey="Count")
82
+ # list(section, keyfmt, countkey="Count", :default => "default value")
83
+ # list(section, keyfmt, countkey="Count", :cipher => true)
84
+ # list(section, keyfmt, countkey="Count", :cipher => true, :default => "default value")
85
+ # list(section, keyfmt, countkey="Count", :ini => ini_filename)
86
+ # list(section, keyfmt, countkey="Count", :ini => ini_filename, :default => "default value")
87
+ #
88
+ # 以下のような連番キーのデータをすべて読み込み配列で返します。
89
+ #
90
+ # [History2]
91
+ # SearchCount=2
92
+ # Search-data0="Ruby"
93
+ # Search-data1="Sleipnir"
94
+ #
95
+ # * +keyfmt+ には連番キーを生成するためのテンプレート文字列を指定します。
96
+ # テンプレート文字列からフォーマット文字列への変換ルールは #list_key_format を参照してください。
97
+ # * +countkey+ には連番キーの個数を記録しているキー名を指定します。
98
+ # デフォルトは "Count" です。
99
+ # * +opts+ の説明は #get_string を参照してください。
100
+ # * +block+ を指定するとフォーマットされた連番キー(文字列)を引数に block を評価して
101
+ # その結果を返します。
102
+ #
103
+ # 例:
104
+ #
105
+ # pnir = SleipnirAPI.connect
106
+ # prof = pnir.profile
107
+ # prof.list("History2", "Search-data0", "SearchCount", :ini => "History.ini") #=> ["Ruby", "Sleipnir"]
108
+ #
109
+ # See Also: #list_key_format
110
+ def list(section, keyfmt, countkey="Count", opts = nil, &block)
111
+ keyfmt = list_key_format(keyfmt)
112
+ block ||= lambda {|key| get_string(section, key, opts) }
113
+ (0...get_int(section, countkey, opts)).map{|i| keyfmt % i }.map(&block)
114
+ end
115
+
116
+ # 連番キーを生成するためのフォーマット文字列を返します。
117
+ #
118
+ # フォーマット文字列は以下のルールで生成します。
43
119
  #
120
+ # * 引数に「%(数字)d」が含まれていればそのまま返す。
121
+ # * 引数に連続する 0 があれば、そこを連番箇所と判断して %d に変換して返す。
122
+ # * 0 が複数箇所に存在する場合は最後の 0 が利用される
123
+ # * 連続する 0 の場合、幅指定のフォーマットになる
124
+ # * 0 が存在しない場合は、以下の場所を連番箇所と判断して %d に変換して返す。
125
+ # * 最初のアンダースコアの前
126
+ # * 文字列末尾
127
+ #
128
+ # 例:
129
+ #
130
+ # list_key_format("Search-data%d") #=> Search-data%d
131
+ #
132
+ # list_key_format("Foo_Bar0_Name") #=> Foo_Bar%d_Name
133
+ # list_key_format("Foo0_Bar0_Name") #=> Foo0_Bar%d_Name
134
+ # list_key_format("Foo0_Bar000_Name") #=> Foo0_Bar%03d_Name
135
+ #
136
+ # list_key_format("Foo_Bar_Name") #=> Foo%d_Bar_Name
137
+ # list_key_format("Name") #=> Name%d
138
+ #
139
+ def list_key_format(keyfmt)
140
+ return keyfmt if keyfmt =~ /%\d*d/
141
+ return keyfmt if keyfmt.sub!(/(0+)(\D*)\z/) {
142
+ n = $1.length
143
+ (n == 1) ? "%d#{$2}" : "%0#{n}d#{$2}"
144
+ }
145
+ return keyfmt.sub(/(_|\z)/) { "%d#{$1}" }
146
+ end
147
+
44
148
  # call-seq:
45
149
  # get_string(section, key)
46
150
  # get_string(section, key, :default => "default value")
@@ -61,7 +165,8 @@ module SleipnirAPI
61
165
  # 同時に指定した場合 <tt>:cipher</tt> は無視されます。
62
166
  #
63
167
  def get_string(section, key, opts = nil)
64
- opts ||= {}
168
+ section, key = str(section, key)
169
+ opts = options(opts, :cipher, :ini, :default)
65
170
  if opts[:ini]
66
171
  api.GetProfileStringEx(section, key, opts[:default], expand_user_path(opts[:ini]))
67
172
  elsif opts[:cipher]
@@ -71,7 +176,6 @@ module SleipnirAPI
71
176
  end
72
177
  end
73
178
 
74
- #
75
179
  # call-seq:
76
180
  # get_int(section, key)
77
181
  # get_int(section, key, :default => -1)
@@ -84,7 +188,8 @@ module SleipnirAPI
84
188
  # 詳細は get_string を参照してください。
85
189
  #
86
190
  def get_int(section, key, opts = nil)
87
- opts ||= {}
191
+ section, key = str(section, key)
192
+ opts = options(opts, :cipher, :ini, :default)
88
193
  if opts[:ini]
89
194
  api.GetProfileIntEx(section, key, opts[:default], expand_user_path(opts[:ini]))
90
195
  elsif opts[:cipher]
@@ -94,7 +199,6 @@ module SleipnirAPI
94
199
  end
95
200
  end
96
201
 
97
- #
98
202
  # call-seq:
99
203
  # write_string(section, key, data)
100
204
  # write_string(section, key, data, :cipher => true)
@@ -104,7 +208,9 @@ module SleipnirAPI
104
208
  # * <tt>:cipher</tt> に true を指定すると暗号化してデータを書き込みます。
105
209
  #
106
210
  def write_string(section, key, data, opts = nil)
107
- opts ||= {}
211
+ section, key = str(section, key)
212
+ check_data(section, key, data, String)
213
+ opts = options(opts, :cipher)
108
214
  if opts[:cipher]
109
215
  api.WriteProfileStringCipher(section, key, data)
110
216
  else
@@ -112,7 +218,6 @@ module SleipnirAPI
112
218
  end
113
219
  end
114
220
 
115
- #
116
221
  # call-seq:
117
222
  # write_int(section, key, data)
118
223
  # write_int(section, key, data, :cipher => true)
@@ -122,7 +227,9 @@ module SleipnirAPI
122
227
  # * <tt>:cipher</tt> に true を指定すると暗号化してデータを書き込みます。
123
228
  #
124
229
  def write_int(section, key, data, opts = nil)
125
- opts ||= {}
230
+ section, key = str(section, key)
231
+ check_data(section, key, data, Integer)
232
+ opts = options(opts, :cipher)
126
233
  if opts[:cipher]
127
234
  api.WriteProfileIntCipher(section, key, data)
128
235
  else
@@ -132,19 +239,51 @@ module SleipnirAPI
132
239
 
133
240
  # <ini_dir>\script.ini から指定されたキーを削除します。
134
241
  def delete(section, key)
242
+ section, key = str(section, key)
135
243
  api.DeleteProfileKey(section, key)
136
244
  end
137
245
 
138
- # <ini_dir> から expand_path します。
246
+ # SleipnirAPI::Sleipnir#user_path から expand_path します。
247
+ #
248
+ # * 引数は to_s で文字列に変換されます。
249
+ # * 拡張子がなければ .ini を付与します。
250
+ #
139
251
  def expand_user_path(ini)
140
- File.expand_path(ini, sleipnir.user_path)
252
+ raise ArgumentError, "Invalid ini file name: #{ini.inspect}" if ini.nil? or ini == ""
253
+ ini = ini.to_s
254
+ if File.extname(ini) == ""
255
+ ini = File.basename(ini, ".*") + ".ini"
256
+ end
257
+ File.expand_path(ini, @user_path)
141
258
  end
142
259
 
143
260
  # <ini_dir>\script.ini のパスを返します。
144
- def script_ini
261
+ def script_ini_path
145
262
  expand_user_path("script.ini")
146
263
  end
147
264
 
265
+ # 指定された ini ファイルを操作する Sleipnir::Profile::Ini オブジェクトを返します。
266
+ #
267
+ # pnir = SleipnirAPI.connect
268
+ # proxy = pnir.profile.ini("Proxy.ini", :default => 123)
269
+ # proxy.get_int("Proxy", "Count")
270
+ #
271
+ # See Also: #method_missing
272
+ def ini(name, opts = nil)
273
+ Ini.new(self, str(name), options(opts))
274
+ end
275
+
276
+ # メソッド名を ini ファイル名とみなして Sleipnir::Profile::Ini オブジェクトを返します。
277
+ #
278
+ # pnir = SleipnirAPI.connect
279
+ # proxy = pnir.profile.Proxy(:default => 123)
280
+ # proxy.get_int("Proxy", "Count")
281
+ #
282
+ # See Also: #ini
283
+ def method_missing(mid, *args, &block)
284
+ ini(mid.to_s, *args, &block)
285
+ end
286
+
148
287
  end
149
288
  end
150
289
 
@@ -0,0 +1,202 @@
1
+ require "sleipnir_api/util"
2
+ require "sleipnir_api/profile/util"
3
+
4
+ module SleipnirAPI
5
+ class Profile
6
+
7
+ # ini ファイルに対応するオブジェクトです。
8
+ # このオブジェクトは SleipnirAPI::Sleipnir#profile で
9
+ # または SleipnirAPI::Profile#ini で取得します。
10
+ #
11
+ # pnir = SleipnirAPI.new
12
+ # ini = pnir.profile("CloseURL.ini")
13
+ # ini.get_string("ClosedURL2", "URL0") #=> "http://hogehoge"
14
+ #
15
+ # #section でこの ini ファイル内のセクションに対応する SleipnirAPI::Profile::Section
16
+ # オブジェクトを取得できます。
17
+ class Ini < ProfileElement
18
+
19
+ # SleipnirAPI::Profile オブジェクトを返します。
20
+ attr_reader :profile
21
+
22
+ # ini ファイル名を返します。
23
+ # これは、SleipnirAPI::Profile#ini に指定した値をそのまま返します。
24
+ # フルパスを得たい場合は #path を利用してください。
25
+ attr_reader :name
26
+
27
+ # #get_string などに指定するデフォルトの引数を取得します。
28
+ # 値は #profile から引き継いでいます。
29
+ attr_reader :default_opts
30
+
31
+ def initialize(profile, name, default_opts = nil)
32
+ super(nil, default_opts)
33
+ @profile = profile
34
+ @name = (name == "" ? nil : name)
35
+ end
36
+
37
+ # call-seq:
38
+ # list(section, keyfmt, countkey="Count")
39
+ # list(section, keyfmt, countkey="Count", :default => "default value")
40
+ # list(section, keyfmt, countkey="Count", :cipher => true)
41
+ # list(section, keyfmt, countkey="Count", :cipher => true, :default => "default value")
42
+ #
43
+ # この ini ファイルから連番キーのデータをすべて読み込み配列で返します。
44
+ #
45
+ # 例:
46
+ #
47
+ # pnir = SleipnirAPI.connect
48
+ # proxy_ini = pnir.profile.proxy
49
+ # proxy_ini.list("Proxy", "Proxy0_Title")
50
+ #
51
+ # See Also: SleipnirAPI::Profile#list
52
+ def list(section, keyfmt, countkey="Count", opts = nil, &block)
53
+ @profile.list(section, keyfmt, countkey, get_options(opts), &block)
54
+ end
55
+
56
+ # call-seq:
57
+ # get_string(section, key)
58
+ # get_string(section, key, :default => "default value")
59
+ # get_string(section, key, :cipher => true)
60
+ # get_string(section, key, :cipher => true, :default => "default value")
61
+ #
62
+ # この ini ファイルから string 型データを読み込みます。
63
+ #
64
+ # See Also: SleipnirAPI::Profile#get_string
65
+ def get_string(section, key, opts = nil)
66
+ @profile.get_string(section, key, get_options(opts))
67
+ end
68
+
69
+ # call-seq:
70
+ # get_int(section, key)
71
+ # get_int(section, key, :default => -1)
72
+ # get_int(section, key, :cipher => true)
73
+ # get_int(section, key, :cipher => true, :default => -1)
74
+ #
75
+ # この ini ファイルから int 型データを読み込みます。
76
+ #
77
+ # See Also: SleipnirAPI::Profile#get_int
78
+ def get_int(section, key, opts = nil)
79
+ @profile.get_int(section, key, get_options(opts))
80
+ end
81
+
82
+ # call-seq:
83
+ # write_string(section, key, data)
84
+ # write_string(section, key, data, :cipher => true)
85
+ #
86
+ # <ini_dir>\script.ini に string 型データを書き込みます。
87
+ # script.ini でない場合は SleipnirAPI::Profile::ReadOnlyError を raise します。
88
+ #
89
+ # * <tt>:cipher</tt> に true を指定すると暗号化してデータを書き込みます。
90
+ #
91
+ # See Also: SleipnirAPI::Profile#write_string
92
+ def write_string(section, key, data, opts = nil)
93
+ check_writable
94
+ @profile.write_string(section, key, data, write_options(opts))
95
+ end
96
+
97
+ # call-seq:
98
+ # write_int(section, key, data)
99
+ # write_int(section, key, data, :cipher => true)
100
+ #
101
+ # <ini_dir>\script.ini に int 型データを書き込みます。
102
+ # script.ini でない場合は SleipnirAPI::Profile::ReadOnlyError を raise します。
103
+ #
104
+ # * <tt>:cipher</tt> に true を指定すると暗号化してデータを書き込みます。
105
+ #
106
+ # See Also: SleipnirAPI::Profile#write_int
107
+ def write_int(section, key, data, opts = nil)
108
+ check_writable
109
+ @profile.write_int(section, key, data, write_options(opts))
110
+ end
111
+
112
+ # <ini_dir>\script.ini から指定されたキーを削除します。
113
+ #
114
+ # script.ini でない場合は SleipnirAPI::Profile::ReadOnlyError を raise します。
115
+ #
116
+ # See Also: SleipnirAPI::Profile#delete
117
+ def delete(section, key)
118
+ check_writable
119
+ @profile.delete(section, key)
120
+ end
121
+
122
+ # script.ini でない場合は SleipnirAPI::Profile::ReadOnlyError を raise します。
123
+ def check_writable
124
+ raise ReadOnlyError, "`#{path}' is not writable" if read_only?
125
+ end
126
+
127
+ # この ini ファイルのフルパスを返します。
128
+ def path
129
+ if script_ini?
130
+ @profile.script_ini_path
131
+ else
132
+ @profile.expand_user_path(@name)
133
+ end
134
+ end
135
+ alias to_s path
136
+
137
+ # <ini_dir>\script.ini なら true を返します。
138
+ def script_ini?
139
+ return true if @name.nil?
140
+ a = @profile.expand_user_path(@name)
141
+ b = @profile.script_ini_path
142
+ a.match(/\A#{Regexp.quote(b)}\z/i) ? true : false
143
+ end
144
+
145
+ # <ini_dir>\script.ini 以外なら true を返します。
146
+ def read_only?
147
+ not script_ini?
148
+ end
149
+
150
+ # 指定されたセクションを操作する Sleipnir::Profile::Section オブジェクトを返します。
151
+ #
152
+ # pnir = SleipnirAPI.connect
153
+ # proxy = pnir.profile.ini("Proxy.ini", :default => 123)
154
+ # sec = proxy.section("Proxy")
155
+ # sec.get_int("Count")
156
+ #
157
+ # See Also: #method_missing
158
+ def section(name, opts = nil)
159
+ Section.new(self, str(name), options(opts))
160
+ end
161
+
162
+ # メソッド名をセクション名とみなして Sleipnir::Profile::Section オブジェクトを返します。
163
+ #
164
+ # pnir = SleipnirAPI.connect
165
+ # proxy = pnir.profile.Proxy(:default => 123)
166
+ # sec = proxy.Proxy
167
+ # sec.get_int("Count")
168
+ #
169
+ # See Also: #section
170
+ def method_missing(mid, *args, &block)
171
+ section(mid.to_s, *args, &block)
172
+ end
173
+
174
+
175
+ def get_options(opts = nil)
176
+ args = options(opts, :cipher, :ini, :default)
177
+
178
+ r = {}
179
+ r[:default] = args.delete(:default) if args.key?(:default)
180
+ if script_ini?
181
+ r[:cipher] = args.delete(:cipher) if args.key?(:cipher)
182
+ else
183
+ r[:ini] = @name
184
+ end
185
+
186
+ unless args.empty?
187
+ raise ArgumentError, "Invalid argument: #{args.inspect} (#{path})"
188
+ end
189
+ r
190
+ end
191
+ private :get_options
192
+
193
+ def write_options(opts = nil)
194
+ r = get_options(opts)
195
+ r.delete(:default)
196
+ r
197
+ end
198
+ private :write_options
199
+
200
+ end
201
+ end
202
+ end