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 CHANGED
@@ -1 +1 @@
1
- 0.5.4
1
+ 0.5.5
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "epitools"
8
- s.version = "0.5.4"
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-04-28"
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"
@@ -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'
@@ -193,6 +193,8 @@ module Enumerable
193
193
  def deep_select(depth=nil, &block)
194
194
  map do |*args|
195
195
 
196
+ obj = args.last
197
+
196
198
  if depth.nil? or depth > 0
197
199
 
198
200
  case obj
@@ -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
@@ -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
@@ -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
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-04-28 00:00:00.000000000 Z
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: