tagen 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.
Files changed (51) hide show
  1. data/.gitignore +2 -0
  2. data/.yardopts +5 -0
  3. data/Gemfile +7 -0
  4. data/Gemfile.lock +24 -0
  5. data/README.md +60 -0
  6. data/Rakefile +9 -0
  7. data/docs/Architecture.md +17 -0
  8. data/docs/CoreExtensions.md +56 -0
  9. data/docs/ExtraExtensions.md +20 -0
  10. data/lib/tagen/audioinfo.rb +21 -0
  11. data/lib/tagen/cairo.rb +809 -0
  12. data/lib/tagen/core.rb +34 -0
  13. data/lib/tagen/core/array.rb +41 -0
  14. data/lib/tagen/core/array/extract_options.rb +40 -0
  15. data/lib/tagen/core/hash.rb +17 -0
  16. data/lib/tagen/core/io.rb +29 -0
  17. data/lib/tagen/core/kernel.rb +73 -0
  18. data/lib/tagen/core/marshal.rb +34 -0
  19. data/lib/tagen/core/module.rb +25 -0
  20. data/lib/tagen/core/numeric.rb +10 -0
  21. data/lib/tagen/core/object.rb +21 -0
  22. data/lib/tagen/core/pa.rb +187 -0
  23. data/lib/tagen/core/pa/cmd.rb +374 -0
  24. data/lib/tagen/core/pa/dir.rb +144 -0
  25. data/lib/tagen/core/pa/path.rb +190 -0
  26. data/lib/tagen/core/pa/state.rb +56 -0
  27. data/lib/tagen/core/process.rb +11 -0
  28. data/lib/tagen/core/re.rb +8 -0
  29. data/lib/tagen/core/string.rb +43 -0
  30. data/lib/tagen/core/string/pyformat.rb +322 -0
  31. data/lib/tagen/core/time.rb +8 -0
  32. data/lib/tagen/gdk_pixbuf2.rb +26 -0
  33. data/lib/tagen/gtk2.rb +122 -0
  34. data/lib/tagen/magick.rb +23 -0
  35. data/lib/tagen/ncurses.rb +245 -0
  36. data/lib/tagen/net/http.rb +34 -0
  37. data/lib/tagen/pathname.rb +8 -0
  38. data/lib/tagen/poppler.rb +47 -0
  39. data/lib/tagen/socket.rb +20 -0
  40. data/lib/tagen/tree.rb +75 -0
  41. data/lib/tagen/vim.rb +19 -0
  42. data/lib/tagen/xmpp4r.rb +1 -0
  43. data/lib/tagen/xmpp4r/roster.rb +20 -0
  44. data/spec/cairo_spec.rb +137 -0
  45. data/spec/core/pa/cmd_spec.rb +251 -0
  46. data/spec/core/pa/dir_spec.rb +59 -0
  47. data/spec/core/string/pyformat_spec.rb +86 -0
  48. data/spec/spec_helper.rb +0 -0
  49. data/tagen.gemspec +20 -0
  50. data/version.rb +7 -0
  51. metadata +117 -0
@@ -0,0 +1,190 @@
1
+ class Pa
2
+ module Path
3
+
4
+ # alias from File.absolute_path
5
+ # @param [String] path
6
+ # @return [String]
7
+ def absolute(path); File.absolute_path(get(path)) end
8
+
9
+ # alias from File.expand_path
10
+ # @param [String] path
11
+ # @return [String]
12
+ def expand(path); File.expand_path(get(path)) end
13
+
14
+ # print current work directory
15
+ # @return [String] path
16
+ def pwd() Dir.getwd end
17
+
18
+ # change directory
19
+ #
20
+ # @param [String] path
21
+ def cd(path=ENV["HOME"], &blk) Dir.chdir(get(path), &blk) end
22
+
23
+ # get path of an object.
24
+ #
25
+ # return obj#path if object has a 'path' instance method
26
+ #
27
+ # @param [String,Pa] obj
28
+ # @return [String,nil] path
29
+ def get obj
30
+ return obj if String === obj
31
+
32
+ begin
33
+ obj.path
34
+ rescue NoMethodError
35
+ raise Error, "not support type -- #{obj.inspect}(#{obj.class})"
36
+ end
37
+ end
38
+
39
+ # extname of a path
40
+ #
41
+ # @example
42
+ # "a.ogg" => "ogg"
43
+ # "a" => nil
44
+ #
45
+ # @param [String] path
46
+ # @return [String]
47
+ def extname path
48
+ _, ext = get(path).match(/\.([^.]+)$/).to_a
49
+ ext
50
+ end
51
+
52
+ # is path an absolute path ?
53
+ #
54
+ # @param [String] path
55
+ # @return [Boolean]
56
+ def absolute?(path) absolute(path) == get(path) end
57
+
58
+ # get a basename of a path
59
+ #
60
+ # @param [String] name
61
+ # @param [Hash] o options
62
+ # @option o [Boolean, String] :ext (false) return \[name, ext] if true
63
+ #
64
+ # @return [String] basename of a path
65
+ # @return [Array<String,String>] \[name, ext] if o[:ext] is true
66
+ def basename(name, o={})
67
+ name = File.basename(get(name))
68
+ if o[:ext]
69
+ _, name, ext = name.match(/^(.+?)(\.[^.]+)?$/).to_a
70
+ [ name, (ext || "")]
71
+ else
72
+ name
73
+ end
74
+ end
75
+
76
+ # split path
77
+ #
78
+ # @example
79
+ # path="/home/a/file"
80
+ # split(path) #=> "/home/a", "file"
81
+ # split(path, :all) #=> "/", "home", "a", "file"
82
+ #
83
+ # @param [String] name
84
+ # @param [Hash] o option
85
+ # @option o [Boolean] :all split all parts
86
+ # @return [Array<String>]
87
+ def split(name, o={})
88
+ dir, fname = File.split(get(name))
89
+ ret = Array.wrap(basename(fname, o))
90
+
91
+ if o[:all]
92
+ loop do
93
+ dir1, fname = File.split(dir)
94
+ break if dir1 == dir
95
+ ret.unshift fname
96
+ dir = dir1
97
+ end
98
+ end
99
+ ret.unshift dir
100
+ ret
101
+ end
102
+
103
+ # join paths, skip nil and empty string.
104
+ #
105
+ # @param [*Array<String>] *paths
106
+ # @return [String]
107
+ def join *paths
108
+ paths.map!{|v|get(v)}
109
+
110
+ # skip nil
111
+ paths.compact!
112
+
113
+ # skip empty string
114
+ paths.delete("")
115
+
116
+ File.join(*paths)
117
+ end
118
+
119
+ # get parent path
120
+ #
121
+ # @param [String] path
122
+ # @return [String]
123
+ def parent path
124
+ join(get(path), "..")
125
+ end
126
+
127
+ # link
128
+ #
129
+ # @overload ln(src, dest)
130
+ # @overload ln([src,..], directory)
131
+ #
132
+ # @param [Array<String>, String] src_s support globbing
133
+ # @param [String] dest
134
+ # @param [Hash] o option
135
+ # @option o [Boolean] :force overwrite if exists.
136
+ # @return [nil]
137
+ def ln(src_s, dest, o={}) _ln(File.method(:link), src_s, dest, o) end
138
+
139
+ # ln force
140
+ #
141
+ # @see ln
142
+ # @return [nil]
143
+ def ln_f(src_s, dest, o) o[:force]=true; _ln(File.method(:link), src_s, dest, o) end
144
+
145
+ # symbol link
146
+ #
147
+ # @see ln
148
+ # @return [nil]
149
+ def symln(src_s, dest, o) _ln(File.method(:symlink), src_s, dest, o) end
150
+ alias symlink ln
151
+
152
+ # symln force
153
+ #
154
+ # @see ln
155
+ # @return [nil]
156
+ def symln_f(src_s, dest, o) o[:force]=true; _ln(File.method(:symlink), src_s, dest, o) end
157
+
158
+ # param
159
+ def _ln(method, src_s, dest, o={})
160
+ dest = Pa(dest)
161
+ glob(*Array.wrap(src_s)) {|src|
162
+ dest = dest.join(src.b) if dest.directory?
163
+ rm_r(dest) if o[:force] and dest.exists?
164
+ method.call(src.p, dest.p)
165
+ }
166
+ end
167
+ private :_ln
168
+
169
+ # @see File.readlink
170
+ def readlink(path) File.readlink(get(path)) end
171
+
172
+
173
+ # is path a dangling symlink?
174
+ #
175
+ # a dangling symlink is a dead symlink.
176
+ #
177
+ # @param [String] path
178
+ # @return [Boolean]
179
+ def dangling? path
180
+ path=get(path)
181
+ if symlink?(path)
182
+ src = readlink(path)
183
+ not exists?(src)
184
+ else
185
+ nil
186
+ end
187
+ end # def dsymlink?
188
+
189
+ end
190
+ end
@@ -0,0 +1,56 @@
1
+ class Pa
2
+ module State
3
+
4
+ # @see File.chmod
5
+ def chmod(mode, *paths) paths.map!{|v|get(v)}; File.chmod(mode, *paths) end
6
+
7
+ # @see File.lchmod
8
+ def lchmod(mode, *paths) paths.map!{|v|get(v)}; File.lchmod(mode, *paths) end
9
+
10
+ # @see File.chown
11
+ def chown(user, group, *paths) paths.map!{|v|get(v)}; File.chown(user, group, *paths) end
12
+
13
+ # @see File.lchown
14
+ def lchown(user, group, *paths) paths.map!{|v|get(v)}; File.lchown(user, group, *paths) end
15
+
16
+ # @see File.utime
17
+ def utime(atime, mtime, *paths) paths.map!{|v|get(v)}; File.utime(atime, mtime, *paths) end
18
+
19
+
20
+ # get file type
21
+ #
22
+ # file types:
23
+ # "chardev" "blockdev" "symlink" ..
24
+ #
25
+ # @param [String] path
26
+ # @return [String]
27
+ def type(path)
28
+ case (t=ftype(get(path)))
29
+ when "characterSpecial"
30
+ "chardev"
31
+ when "blockSpecial"
32
+ "blockdev"
33
+ when "link"
34
+ "symlink"
35
+ else
36
+ t
37
+ end
38
+ end # def type
39
+
40
+
41
+ # is path a mountpoint?
42
+ #
43
+ # @param[String] path
44
+ # @return [Boolean]
45
+ def mountpoint? path
46
+ path=get(path)
47
+ begin
48
+ stat1 = path.lstat
49
+ stat2 = path.parent.lstat
50
+ stat1.dev == stat2.dev && stat1.ino == stat2.ino || stat1.dev != stat2.dev
51
+ rescue Errno::ENOENT
52
+ false
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,11 @@
1
+ module Process
2
+ # check if the pid's process is running.
3
+ #
4
+ # @note for linux only
5
+ # @param [String, Integer] pid process id
6
+ # @return [Boolean]
7
+ def self.exists?(pid)
8
+ raise NotImplementError unless linux?
9
+ File.exists?("/proc/#{pid}")
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ class MatchData
2
+ # group-name regexp
3
+ # @return [Hash] {:name => "mathed-data"}
4
+ def to_hash
5
+ Hash[names.map(&:to_sym).zip(captures)]
6
+ end
7
+ end
8
+
@@ -0,0 +1,43 @@
1
+ class String
2
+ @@didits = "0123456789"
3
+ @@hexdigits = "01234567890ABCDEF"
4
+ @@octdigits = "01234567"
5
+ @@uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
6
+ @@lowercase = "abcdefghijklmnopqrstuvwxyz"
7
+ @@letters = @@uppercase + @@lowercase
8
+
9
+ class << self
10
+
11
+ # "0123456789"
12
+ #
13
+ # @return [String]
14
+ def digits; @@digits end
15
+
16
+ # "01234567890ABCDEF"
17
+ #
18
+ # @return [String]
19
+ def hexdigits; @@hexdigits end
20
+
21
+ # "01234567"
22
+ #
23
+ # @return [String]
24
+ def octdigits; @@octdigits end
25
+
26
+ # "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
27
+ #
28
+ # @return [String]
29
+ def uppercase; @@uppercase end
30
+
31
+ # "abcdefghijklmnopqrstuvwxyz"
32
+ #
33
+ # @return [String]
34
+ def lowercase; @@lowercase end
35
+
36
+ # "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
37
+ #
38
+ # @return [String]
39
+ def letters; @@letters end
40
+ end
41
+ end # class String
42
+
43
+ require_relative "string/pyformat"
@@ -0,0 +1,322 @@
1
+ =begin
2
+ == Overview
3
+ a python like string format libraray.
4
+
5
+ 1. "this is #{guten}" # Ruby Builtin
6
+ 2. "this is %s" % "guten" # Ruby Builtin
7
+ 3. "this is {guten}".format(guten: 'x')
8
+
9
+ use "#{var}" is easy and quick in many cases, but some times we need a more powerful format support.
10
+ "I like %s and %s" % %(apple, football)
11
+ "I like {fruit} and {sport}".format(%w(apple football)) # it has semantic meaning.
12
+
13
+ == Usage
14
+ require "tagen/core"
15
+ "it costs {:.2f} dollar".format(1.123) #=> "it costs 1.12 dollar"
16
+
17
+ * support abritry-argument or hash-argument
18
+ "{} {}".format(1,2) #=> "1 2"
19
+ "{a} {b}".format(a:1, b:2) #=> "1 2"
20
+ "{a} {b}".format(1, b:2) #=> "1 2"
21
+
22
+ * escape
23
+ "my {{name}} is {name}".format("guten") #=> my name is guten.
24
+
25
+ == Examples
26
+ "{:.2f}"
27
+ "{name:.2f}"
28
+
29
+ == Specification
30
+ format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]
31
+ fill ::= <a character other than '}'> default is " "
32
+ align ::= "<" | ">" | "=" | "^" default is >. = is padding after sign. eg. +000000120
33
+ sign ::= "+" | "-" | " "
34
+ # ::= <prefix 0b 0o 0x>
35
+ 0 ::= <zero_padding> equal to fill is 0
36
+ , ::= <comma_sep> also type n
37
+ precision ::= string truncate with
38
+ type ::= s c b o d x X ¦ f/F g/G e/E n %
39
+
40
+ f/F fixed point. nan/NAN inf/INF
41
+ e/E exponent notation.
42
+ g/G gernal format. 1.0 => 1
43
+ n number. thounds sep based on local setting
44
+
45
+ == Resources
46
+ * http://docs.python.org/py3k/library/string.html#formatstrings
47
+
48
+ =end
49
+ class PyFormat
50
+ Error = Class.new Exception
51
+ EFormatSpec = Class.new Error
52
+ EFieldName = Class.new Error
53
+
54
+ # @param [String] fmt
55
+ def initialize fmt
56
+ @fmt = fmt
57
+ end
58
+
59
+ # format a string
60
+ #
61
+ # @param [Object] *args
62
+ # @return [String]
63
+ def format *args
64
+ # if 'field' in argh
65
+ # return argh[field]
66
+ # else
67
+ # return args.shift
68
+ # end
69
+
70
+ # args -> argh and args
71
+ argh = Hash===args[-1] ? args.pop : {}
72
+
73
+ # "{0:.5f}"
74
+ pat = /{{.*?}} | { (.*?)? (?: :(.*?) )? } /x
75
+ ret = @fmt.gsub(pat) do |m|
76
+ if m.start_with? "{{"
77
+ m
78
+ else
79
+ field, spec = $1, $2
80
+ field = field.to_sym
81
+
82
+ if argh.has_key? field
83
+ arg = argh[field]
84
+ else
85
+ arg = args.shift
86
+
87
+ # can't use if arg==nil then ..
88
+ #
89
+ # class Guten
90
+ # def <=> other
91
+ # "{}".format(self)
92
+ # end
93
+ #
94
+ # => SystemStackError
95
+ #
96
+ if NilClass === arg then raise EFieldName, "not enought arguments --#{args}" end
97
+ end
98
+
99
+ Field.parse spec, arg
100
+ end
101
+ end
102
+ ret
103
+ end
104
+
105
+ class Field
106
+ PAT = /^
107
+ (?: (?<fill>[^}]+)? (?<align>[<>=^]) )?
108
+ (?<sign>[ +-])?
109
+ (?<alternate>\#)?
110
+ (?<zero_padding>0)?
111
+ (?<width>\d+)?
112
+ (?<comma_sep>,)?
113
+ (?: \.(?<precision>\d+) )?
114
+ (?<type>[bcdeEfFgGnosxX%])? /x
115
+
116
+
117
+ def self.parse spec, arg
118
+ f = self.new
119
+ f.parse_spec spec if spec
120
+ f.format arg
121
+ end
122
+
123
+ def initialize
124
+ # default options
125
+ @o = {
126
+ fill: " ",
127
+ align: ">",
128
+ sign: "-",
129
+ alternate: false,
130
+ zero_padding: false,
131
+ width: 0,
132
+ comma_sep: false,
133
+ precision: nil,
134
+ type: nil,
135
+ }
136
+ end
137
+
138
+ # parse a spec string
139
+ #
140
+ # parse_spec "this is {:.2f}"
141
+ # return @o
142
+ #
143
+ # @param [String] spec
144
+ # @return [nil]
145
+ def parse_spec spec
146
+ matched = PAT.match(spec)
147
+ raise EFormatSpec, spec if not matched
148
+ matched = matched.to_hash
149
+
150
+ # merge @o and matched
151
+ @o.each do |k,v|
152
+ @o[k] = matched[k] ? matched[k] : v
153
+ end
154
+
155
+ # handle keys
156
+ @o = @o.each.with_object({}) do |(k,v),o|
157
+ case k
158
+ when :width, :precision
159
+ o[k] = v.to_i if v
160
+ when :zero_padding
161
+ if v
162
+ o[:fill] = "0"
163
+ end
164
+ when :precision
165
+ o[:precision] = 1 if v<1
166
+ else
167
+ o[k] = v
168
+ end
169
+ end
170
+
171
+ if @o[:align] == "="
172
+ @o[:fill] = "0"
173
+ @o[:sign] = "+"
174
+ end
175
+
176
+ end
177
+
178
+ # format a <#Field> by @o
179
+ #
180
+ # @param [Object] arg
181
+ # @return [String]
182
+ def format arg
183
+ # arg is int str ..
184
+ # ret is str.
185
+
186
+ case arg
187
+ when Integer
188
+ @o[:type] ||= 'd'
189
+ else # default is s
190
+ @o[:type] ||= 's'
191
+ end
192
+
193
+ ret = case @o[:type]
194
+ when 's'
195
+ arg = arg.to_s
196
+ @o[:precision] ? arg[0...@o[:precision]] : arg
197
+ when 'c'
198
+ arg.chr
199
+
200
+ when 'b','o','d','x','X'
201
+ arg = arg.to_i
202
+
203
+ case @o[:type]
204
+ when 'b'
205
+ ret1 = arg.to_s 2
206
+ ret1 = do_comma ret1
207
+ @o[:alternate] ? '0b'+ret1 : ret1
208
+ when 'o'
209
+ ret1 = arg.to_s 8
210
+ ret1 = do_comma ret1
211
+ @o[:alternate] ? '0'+ret1 : ret1
212
+ when 'd'
213
+ ret1 = arg.to_s 10
214
+ do_comma ret1
215
+ when 'x', 'X'
216
+ ret1 = arg.to_s 16
217
+ ret1.upcase! if @o[:type]=='X'
218
+ ret1 = do_comma ret1
219
+ @o[:alternate] ? "0#{@o[:type]}"+ret1 : ret1
220
+ end
221
+
222
+ # for float, need handle 'precision'
223
+ when 'f','F','g','G','e','E', '%'
224
+ type = @o[:type]
225
+
226
+ num = arg.to_f
227
+
228
+ if type=='%'
229
+ num = num*100
230
+ type = 'g'
231
+ elsif type=='F'
232
+ type = 'f'
233
+ end
234
+
235
+ # remove 0 1.00000
236
+ if type=='f'
237
+ sa, sb = num.to_s.split('.')
238
+ prec = sb.length
239
+ @o[:precision] = prec if not @o[:precision]
240
+ elsif type=='e'
241
+ # not implement yet
242
+ end
243
+
244
+ spec = "%"
245
+ spec += '.' + @o[:precision].to_s if @o[:precision]
246
+ spec += type
247
+
248
+ ret1 = spec % num
249
+
250
+ # '%g' % 1.0 => 1
251
+
252
+ # 'comma_sep'
253
+ if not %w(g G).include? type
254
+ a, b = ret1.split('.')
255
+ a = do_comma a
256
+ ret1 = b==nil ? a : a+'.'+b
257
+ end
258
+
259
+ ret1 += '%' if @o[:type]=='%'
260
+ ret1
261
+
262
+ end # case
263
+
264
+ ## sign
265
+ if @o[:sign] != '-'
266
+ sign = arg.to_f>=0 ? @o[:sign] : '-'
267
+ ret = sign+ret
268
+ end
269
+
270
+
271
+ ## width
272
+ n = @o[:width] - ret.length
273
+ if n > 0
274
+ fill = ''
275
+ @o[:fill].chars.cycle do |c|
276
+ fill << c
277
+ break if fill.length == n
278
+ end
279
+
280
+ ret = case @o[:align]
281
+ when '>' then fill + ret
282
+ when '<' then ret + fill
283
+ when '^' then fill[0...fill.length/2] + ret + fill[fill.length/2..-1]
284
+ when '=' then ret[0] + fill + ret[1..-1]
285
+ end
286
+
287
+ end
288
+
289
+
290
+ ret
291
+ end # def format
292
+
293
+ private
294
+ # convert '1234' -> ['1', '234'] -> '1,234'
295
+ #
296
+ # loop
297
+ # [l:h]
298
+ # break if h==length
299
+ # l = h ; h += 3
300
+ def do_comma src
301
+ # [l:h]
302
+ l = 0
303
+ h = (src.length % 3)
304
+ srcs = []
305
+
306
+ loop do
307
+ pice = src[l...h]
308
+ srcs << pice if not pice==""
309
+ break if h == src.length
310
+ l = h ; h += 3
311
+ end
312
+
313
+ srcs.join ','
314
+ end
315
+ end # class Field
316
+ end # class PyFormat
317
+
318
+ class String
319
+ def format(*args) PyFormat.new(self).format *args end
320
+ end
321
+
322
+ # vim:foldnestmax=4