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.
- data/.gitignore +2 -0
- data/.yardopts +5 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +24 -0
- data/README.md +60 -0
- data/Rakefile +9 -0
- data/docs/Architecture.md +17 -0
- data/docs/CoreExtensions.md +56 -0
- data/docs/ExtraExtensions.md +20 -0
- data/lib/tagen/audioinfo.rb +21 -0
- data/lib/tagen/cairo.rb +809 -0
- data/lib/tagen/core.rb +34 -0
- data/lib/tagen/core/array.rb +41 -0
- data/lib/tagen/core/array/extract_options.rb +40 -0
- data/lib/tagen/core/hash.rb +17 -0
- data/lib/tagen/core/io.rb +29 -0
- data/lib/tagen/core/kernel.rb +73 -0
- data/lib/tagen/core/marshal.rb +34 -0
- data/lib/tagen/core/module.rb +25 -0
- data/lib/tagen/core/numeric.rb +10 -0
- data/lib/tagen/core/object.rb +21 -0
- data/lib/tagen/core/pa.rb +187 -0
- data/lib/tagen/core/pa/cmd.rb +374 -0
- data/lib/tagen/core/pa/dir.rb +144 -0
- data/lib/tagen/core/pa/path.rb +190 -0
- data/lib/tagen/core/pa/state.rb +56 -0
- data/lib/tagen/core/process.rb +11 -0
- data/lib/tagen/core/re.rb +8 -0
- data/lib/tagen/core/string.rb +43 -0
- data/lib/tagen/core/string/pyformat.rb +322 -0
- data/lib/tagen/core/time.rb +8 -0
- data/lib/tagen/gdk_pixbuf2.rb +26 -0
- data/lib/tagen/gtk2.rb +122 -0
- data/lib/tagen/magick.rb +23 -0
- data/lib/tagen/ncurses.rb +245 -0
- data/lib/tagen/net/http.rb +34 -0
- data/lib/tagen/pathname.rb +8 -0
- data/lib/tagen/poppler.rb +47 -0
- data/lib/tagen/socket.rb +20 -0
- data/lib/tagen/tree.rb +75 -0
- data/lib/tagen/vim.rb +19 -0
- data/lib/tagen/xmpp4r.rb +1 -0
- data/lib/tagen/xmpp4r/roster.rb +20 -0
- data/spec/cairo_spec.rb +137 -0
- data/spec/core/pa/cmd_spec.rb +251 -0
- data/spec/core/pa/dir_spec.rb +59 -0
- data/spec/core/string/pyformat_spec.rb +86 -0
- data/spec/spec_helper.rb +0 -0
- data/tagen.gemspec +20 -0
- data/version.rb +7 -0
- 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,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
|