epitools 0.5.4 → 0.5.5
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/VERSION +1 -1
- data/epitools.gemspec +5 -2
- data/lib/epitools/autoloads.rb +3 -1
- data/lib/epitools/core_ext/enumerable.rb +2 -0
- data/lib/epitools/core_ext/string.rb +9 -0
- data/lib/epitools/typed_struct.rb +67 -0
- data/lib/epitools/wm.rb +83 -0
- data/spec/core_ext_spec.rb +6 -0
- data/spec/typed_struct_spec.rb +16 -0
- metadata +5 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.5
|
data/epitools.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "epitools"
|
8
|
-
s.version = "0.5.
|
8
|
+
s.version = "0.5.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["epitron"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-05-01"
|
13
13
|
s.description = "Miscellaneous utility libraries to make my life easier."
|
14
14
|
s.email = "chris@ill-logic.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -60,6 +60,8 @@ Gem::Specification.new do |s|
|
|
60
60
|
"lib/epitools/sys.rb",
|
61
61
|
"lib/epitools/term.rb",
|
62
62
|
"lib/epitools/trie.rb",
|
63
|
+
"lib/epitools/typed_struct.rb",
|
64
|
+
"lib/epitools/wm.rb",
|
63
65
|
"lib/epitools/zopen.rb",
|
64
66
|
"spec/autoreq_spec.rb",
|
65
67
|
"spec/browser_spec.rb",
|
@@ -78,6 +80,7 @@ Gem::Specification.new do |s|
|
|
78
80
|
"spec/spec_helper.rb",
|
79
81
|
"spec/sys_spec.rb",
|
80
82
|
"spec/term_spec.rb",
|
83
|
+
"spec/typed_struct_spec.rb",
|
81
84
|
"spec/zopen_spec.rb"
|
82
85
|
]
|
83
86
|
s.homepage = "http://github.com/epitron/epitools"
|
data/lib/epitools/autoloads.rb
CHANGED
@@ -43,12 +43,14 @@ autoload :Ezdb, 'epitools/ezdb'
|
|
43
43
|
autoload :Browser, 'epitools/browser'
|
44
44
|
autoload :Rash, 'epitools/rash'
|
45
45
|
autoload :Ratio, 'epitools/ratio'
|
46
|
-
autoload :Sys, 'epitools/sys'
|
47
46
|
autoload :ProgressBar, 'epitools/progressbar'
|
48
47
|
autoload :Trie, 'epitools/trie'
|
49
48
|
autoload :MimeMagic, 'epitools/mimemagic'
|
50
49
|
autoload :Term, 'epitools/term'
|
51
50
|
autoload :Iter, 'epitools/iter'
|
51
|
+
autoload :WM, 'epitools/wm'
|
52
|
+
autoload :TypedStruct, 'epitools/typed_struct'
|
53
|
+
autoload :Sys, 'epitools/sys'
|
52
54
|
|
53
55
|
## Gems (common)
|
54
56
|
autoreq :Nokogiri, 'nokogiri'
|
@@ -257,6 +257,15 @@ class String
|
|
257
257
|
end
|
258
258
|
end
|
259
259
|
|
260
|
+
#
|
261
|
+
# Converts time duration strings (mm:ss, hh:mm:ss, or dd:hh:mm:ss) to seconds.
|
262
|
+
# (The reverse of Integer#to_hms)
|
263
|
+
#
|
264
|
+
def from_hms
|
265
|
+
nums = split(':').map(&:to_i)
|
266
|
+
nums_and_units = nums.reverse.zip %w[seconds minutes hours days]
|
267
|
+
nums_and_units.map { |num, units| num.send(units) }.sum
|
268
|
+
end
|
260
269
|
|
261
270
|
unless public_method_defined? :to_proc
|
262
271
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#
|
2
|
+
#
|
3
|
+
#
|
4
|
+
class TypedStruct < Struct
|
5
|
+
|
6
|
+
## TODO: Compact syntax: "a,b,c:int x:string y:date"
|
7
|
+
## TODO: Optional commas separating fields: "a, b, c:int, d:bool"
|
8
|
+
## TODO: booleans fields add "field?" methods
|
9
|
+
|
10
|
+
#
|
11
|
+
# A perhaps-too-clever table of { "typename" => convert_proc } mappings.
|
12
|
+
#
|
13
|
+
CONVERTERS = Hash[ *{
|
14
|
+
|
15
|
+
["str", "string"] => :passthru,
|
16
|
+
["int", "integer"] => proc { |me| me.to_i },
|
17
|
+
["hex"] => proc { |me| me.to_i(16) },
|
18
|
+
["bool", "boolean"] => proc { |me|
|
19
|
+
case me
|
20
|
+
when false, 0, "0", "off", "no", "false", nil
|
21
|
+
false
|
22
|
+
when true, 1, "1", "on", "yes", "true"
|
23
|
+
true
|
24
|
+
else
|
25
|
+
raise "Invalid boolean type: #{me.inspect}"
|
26
|
+
end
|
27
|
+
},
|
28
|
+
["date", "time", "datetime"] => proc { |me| DateTime.parse me },
|
29
|
+
["timestamp"] => proc { |me| Time.at me },
|
30
|
+
|
31
|
+
}.map { |names, converter| names.map { |n| [n, converter] } }.flatten ]
|
32
|
+
|
33
|
+
#
|
34
|
+
# Initialize a new struct.
|
35
|
+
#
|
36
|
+
def self.[](specs)
|
37
|
+
# create [name,type] pairs
|
38
|
+
pairs = specs.split.map do |spec|
|
39
|
+
name, type = spec.split(":")
|
40
|
+
|
41
|
+
type ||= "string"
|
42
|
+
unless converter = CONVERTERS[type]
|
43
|
+
raise "Unknown type: #{type}"
|
44
|
+
end
|
45
|
+
|
46
|
+
[name.to_sym, converter]
|
47
|
+
end
|
48
|
+
|
49
|
+
# initialize the C Struct
|
50
|
+
struct = new(*pairs.transpose.first)
|
51
|
+
|
52
|
+
# overload setter methods to call the proc
|
53
|
+
pairs.each do |field, converter|
|
54
|
+
next if converter == :passthru
|
55
|
+
struct.send(:define_method, "#{field}=") do |val|
|
56
|
+
self[field] = ( val and converter.call val )
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
struct
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize(*args)
|
64
|
+
members.zip(args).each { |field,value| send "#{field}=", value }
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
data/lib/epitools/wm.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module WM
|
2
|
+
|
3
|
+
raise "Error: wmctrl not found." unless Path.which("wmctrl")
|
4
|
+
|
5
|
+
def self.windows; @windows ||= Window.all; end
|
6
|
+
def self.desktops; @desktops ||= Desktop.all; end
|
7
|
+
def self.processes; @processes ||= Hash[ Sys.ps.map { |process| [process.pid, process] } ] ; end
|
8
|
+
def self.current_desktop; @current = desktops.find { |d| d.current? }; end
|
9
|
+
|
10
|
+
class Desktop < TypedStruct["num:int current:bool resolution viewport desktop_geometry name"]
|
11
|
+
def self.all
|
12
|
+
# 0 - DG: 1680x1050 VP: N/A WA: 0,25 1680x974 Workspace 1
|
13
|
+
# 1 - DG: 1680x1050 VP: N/A WA: 0,25 1680x974 Workspace 2
|
14
|
+
# 2 * DG: 1680x1050 VP: 0,0 WA: 0,25 1680x974 Workspace 3
|
15
|
+
# 3 - DG: 1680x1050 VP: N/A WA: 0,25 1680x974 Workspace 4
|
16
|
+
# 4 - DG: 1680x1050 VP: N/A WA: 0,25 1680x974 Workspace 5
|
17
|
+
# 5 - DG: 1680x1050 VP: N/A WA: 0,25 1680x974 Workspace 6
|
18
|
+
# 0 1 2 3 4 5 6 7 8 9
|
19
|
+
`wmctrl -d`.lines.map(&:strip).map { |line| Desktop.from_line(line) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.from_line(line)
|
23
|
+
fields = line.split
|
24
|
+
fields[1] = (fields[1] == "*")
|
25
|
+
fields[5] = nil if fields[5] == "N/A"
|
26
|
+
|
27
|
+
name = fields[9..-1].join(" ")
|
28
|
+
|
29
|
+
new *(fields.values_at(0,1,3,5,8) + [name])
|
30
|
+
end
|
31
|
+
|
32
|
+
def current?
|
33
|
+
current
|
34
|
+
end
|
35
|
+
|
36
|
+
def windows
|
37
|
+
#binding.pry
|
38
|
+
@windows ||= WM.windows.select { |w| w.desktop_id == num }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
class Window < TypedStruct["addr desktop_id:int pid:int x:int y:int w:int h:int hostname title"]
|
44
|
+
|
45
|
+
def self.all
|
46
|
+
`wmctrl -lpG`.lines.map(&:strip).map { |line| Window.from_line(line) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.from_line(line)
|
50
|
+
# 0x01600031 -1 2562 0 0 1680 25 fizz Top Expanded Edge Panel
|
51
|
+
# 0x01600003 -1 2562 0 1998 1680 51 fizz Bottom Expanded Edge Panel
|
52
|
+
# 0x02c0001f 0 3012 849 173 783 667 fizz Terminal
|
53
|
+
# 0x048001f8 5 4080 311 186 1316 835 fizz Gorillaz - Highway (Under Construction)
|
54
|
+
# 0x02c28577 4 3012 66 461 1143 548 fizz Terminal
|
55
|
+
# 0x07c00003 0 14117 12 73 1298 948 fizz tr1984001_comp_soft.pdf
|
56
|
+
# 0x02d767d8 2 3012 520 470 1143 548 fizz Terminal
|
57
|
+
|
58
|
+
fields = line.split
|
59
|
+
title = fields[8..-1].join ' '
|
60
|
+
|
61
|
+
new *(fields[0..7] + [title])
|
62
|
+
end
|
63
|
+
|
64
|
+
def desktop
|
65
|
+
WM.desktops[desktop_id]
|
66
|
+
end
|
67
|
+
|
68
|
+
def sticky?
|
69
|
+
desktop == -1
|
70
|
+
end
|
71
|
+
|
72
|
+
alias_method :name, :title
|
73
|
+
|
74
|
+
def process
|
75
|
+
WM.processes[pid]
|
76
|
+
end
|
77
|
+
|
78
|
+
def inspect
|
79
|
+
"{ ::#{name}:: [#{desktop_id}]}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
data/spec/core_ext_spec.rb
CHANGED
@@ -613,3 +613,9 @@ describe "to_jsons and to_yamls" do
|
|
613
613
|
data.to_yaml.from_yaml.should == data
|
614
614
|
end
|
615
615
|
|
616
|
+
describe "to_hms and from_hms" do
|
617
|
+
60.to_hms.should == "01:00"
|
618
|
+
60.to_hms.from_hms.should == 60
|
619
|
+
"1:20:33".from_hms.to_hms.should == "01:20:33"
|
620
|
+
"5:01:20:33".from_hms.to_hms.should == "05:01:20:33"
|
621
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'epitools'
|
2
|
+
|
3
|
+
describe TypedStruct do
|
4
|
+
|
5
|
+
it "works" do
|
6
|
+
t = TypedStruct["a:int b c:boolean d:timestamp"].new
|
7
|
+
|
8
|
+
t.a.should == nil
|
9
|
+
t.a = "111"; t.a.should == 111
|
10
|
+
t.b = "111"; t.b.should == "111"
|
11
|
+
t.c = "yes"; t.c.should == true
|
12
|
+
#t.c?.should == true
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: epitools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-05-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -110,6 +110,8 @@ files:
|
|
110
110
|
- lib/epitools/sys.rb
|
111
111
|
- lib/epitools/term.rb
|
112
112
|
- lib/epitools/trie.rb
|
113
|
+
- lib/epitools/typed_struct.rb
|
114
|
+
- lib/epitools/wm.rb
|
113
115
|
- lib/epitools/zopen.rb
|
114
116
|
- spec/autoreq_spec.rb
|
115
117
|
- spec/browser_spec.rb
|
@@ -128,6 +130,7 @@ files:
|
|
128
130
|
- spec/spec_helper.rb
|
129
131
|
- spec/sys_spec.rb
|
130
132
|
- spec/term_spec.rb
|
133
|
+
- spec/typed_struct_spec.rb
|
131
134
|
- spec/zopen_spec.rb
|
132
135
|
homepage: http://github.com/epitron/epitools
|
133
136
|
licenses:
|