tagen 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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