gwtf 0.4.4 → 0.4.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/lib/gwtf/commands/edit_command.rb +18 -2
- data/lib/gwtf/commands/list_command.rb +12 -2
- data/lib/gwtf/commands/new_command.rb +5 -0
- data/lib/gwtf/item.rb +49 -101
- data/lib/gwtf/items.rb +5 -2
- data/lib/gwtf/version.rb +1 -1
- data/lib/gwtf.rb +25 -0
- data/lib/objhash.rb +221 -0
- metadata +5 -4
@@ -13,6 +13,7 @@ command [:edit, :vi, :e] do |c|
|
|
13
13
|
begin
|
14
14
|
tmp = Tempfile.new("gwtf")
|
15
15
|
tmp.puts "Subject: %s" % [ item.subject ]
|
16
|
+
tmp.puts "Due Date: %s" % [ item.due_date ]
|
16
17
|
tmp.puts "Description:"
|
17
18
|
tmp.puts item.description if item.description
|
18
19
|
tmp.rewind
|
@@ -23,13 +24,28 @@ command [:edit, :vi, :e] do |c|
|
|
23
24
|
tmp.unlink
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
+
edited_item = edited_item.split("\n")
|
28
|
+
|
29
|
+
if edited_item.first =~ /^Subject:\s*(.+)/
|
27
30
|
item.subject = $1
|
28
31
|
else
|
29
32
|
raise "Subject is required"
|
30
33
|
end
|
31
34
|
|
32
|
-
|
35
|
+
if edited_item[1] =~ /^Due Date:\s*(.+)/
|
36
|
+
if ["", " "].include?($1)
|
37
|
+
item.due_date = nil
|
38
|
+
else
|
39
|
+
item.due_date = $1
|
40
|
+
end
|
41
|
+
else
|
42
|
+
item.due_date = nil # if the user just delete the line from the
|
43
|
+
edited_item.insert(1, "") # treat it as removing the due date but insert
|
44
|
+
# some blank data in the array to not break the
|
45
|
+
# description finding logic
|
46
|
+
end
|
47
|
+
|
48
|
+
description = edited_item[4..-1]
|
33
49
|
|
34
50
|
unless [description].flatten.compact.empty?
|
35
51
|
item.description = description.join("\n")
|
@@ -23,10 +23,20 @@ command [:list, :ls, :l] do |c|
|
|
23
23
|
items = Gwtf::Items.new(File.join(global_options[:data], project), project)
|
24
24
|
stats = items.stats
|
25
25
|
|
26
|
-
|
26
|
+
unless stats["open"] == 0
|
27
|
+
msg = "%#{longest_name + 3}s: open: %-3d closed %-3d overdue: %-3d total: %-3d" % [ project, stats["open"], stats["closed"], stats["overdue"], stats["total"] ]
|
28
|
+
|
29
|
+
if stats["overdue"] > 0
|
30
|
+
puts Gwtf.red(msg)
|
31
|
+
elsif stats["due_soon"] > 0
|
32
|
+
puts Gwtf.yellow(msg)
|
33
|
+
else
|
34
|
+
puts Gwtf.green(msg)
|
35
|
+
end
|
36
|
+
end
|
27
37
|
end
|
28
|
-
|
29
38
|
puts
|
39
|
+
|
30
40
|
elsif options[:overview]
|
31
41
|
Gwtf.projects(global_options[:data]).each do |project|
|
32
42
|
items = Gwtf::Items.new(File.join(global_options[:data], project), project)
|
@@ -1,6 +1,10 @@
|
|
1
1
|
desc 'Create an item'
|
2
2
|
arg_name 'Short item description'
|
3
3
|
command [:new, :add, :n, :a, :c] do |c|
|
4
|
+
c.desc 'Due date for the item (yyyy/mm/dd)'
|
5
|
+
c.default_value false
|
6
|
+
c.flag [:due]
|
7
|
+
|
4
8
|
c.desc 'Invoke EDITOR to provide a long form description'
|
5
9
|
c.default_value false
|
6
10
|
c.switch [:edit, :e]
|
@@ -43,6 +47,7 @@ command [:new, :add, :n, :a, :c] do |c|
|
|
43
47
|
item = @items.new_item
|
44
48
|
item.subject = subject
|
45
49
|
item.description = description if description
|
50
|
+
item.due_date = options[:due] if options[:due]
|
46
51
|
item.save
|
47
52
|
|
48
53
|
if options[:remind]
|
data/lib/gwtf/item.rb
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
module Gwtf
|
2
2
|
class Item
|
3
|
+
include ObjHash
|
4
|
+
|
3
5
|
attr_accessor :file
|
4
6
|
attr_reader :project
|
5
7
|
|
8
|
+
property :description, :default => nil, :validation => String
|
9
|
+
property :subject, :default => nil, :validation => String
|
10
|
+
property :status, :default => "open", :validation => ["open", "closed"]
|
11
|
+
property :item_id, :default => nil, :validation => Integer
|
12
|
+
property :work_log, :default => [], :validation => Array
|
13
|
+
property :due_date, :default => nil, :validation => /^20\d\d[- \/.](0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])$/
|
14
|
+
property :closed_at, :default => nil
|
15
|
+
|
6
16
|
def initialize(file=nil, project=nil)
|
7
|
-
@item = default_item
|
8
17
|
@file = file
|
9
18
|
@project = project
|
10
19
|
|
@@ -12,19 +21,33 @@ module Gwtf
|
|
12
21
|
end
|
13
22
|
|
14
23
|
def open?
|
15
|
-
|
24
|
+
status == "open"
|
16
25
|
end
|
17
26
|
|
18
27
|
def closed?
|
19
28
|
!open?
|
20
29
|
end
|
21
30
|
|
31
|
+
def overdue?
|
32
|
+
if has_due_date? && open?
|
33
|
+
return !!(days_till_due < 0)
|
34
|
+
else
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def days_till_due
|
40
|
+
return 1000 unless has_due_date?
|
41
|
+
|
42
|
+
return (Date.parse(due_date) - Date.today).to_i
|
43
|
+
end
|
44
|
+
|
22
45
|
def load_item
|
23
46
|
raise "A file to read from has not been specified" unless @file
|
24
47
|
|
25
48
|
read_item = JSON.parse(File.read(@file))
|
26
49
|
|
27
|
-
|
50
|
+
merge!(read_item)
|
28
51
|
end
|
29
52
|
|
30
53
|
def backup_dir
|
@@ -32,7 +55,7 @@ module Gwtf
|
|
32
55
|
end
|
33
56
|
|
34
57
|
def save(backup=true)
|
35
|
-
raise "No item_id set, cannot save item" unless
|
58
|
+
raise "No item_id set, cannot save item" unless item_id
|
36
59
|
|
37
60
|
if backup && File.exist?(@file)
|
38
61
|
backup_name = File.basename(@file) + "-" + Time.now.to_f.to_s
|
@@ -47,17 +70,6 @@ module Gwtf
|
|
47
70
|
@file
|
48
71
|
end
|
49
72
|
|
50
|
-
def default_item
|
51
|
-
{"description" => nil,
|
52
|
-
"subject" => nil,
|
53
|
-
"created_at" => Time.now,
|
54
|
-
"edited_at" => nil,
|
55
|
-
"closed_at" => nil,
|
56
|
-
"status" => "open",
|
57
|
-
"item_id" => nil,
|
58
|
-
"work_log" => []}
|
59
|
-
end
|
60
|
-
|
61
73
|
def time_worked
|
62
74
|
work_log.inject(0) do |result, log|
|
63
75
|
begin
|
@@ -74,12 +86,14 @@ module Gwtf
|
|
74
86
|
flag << "closed" if closed?
|
75
87
|
flag << "open" if open?
|
76
88
|
flag << "descr" if description?
|
89
|
+
flag << "overdue" if overdue?
|
77
90
|
flag << work_log.size.to_s unless work_log.empty?
|
78
91
|
flag
|
79
92
|
end
|
80
93
|
|
81
94
|
def compact_flags
|
82
95
|
flags = []
|
96
|
+
flags << "O" if overdue?
|
83
97
|
flags << "D" if has_description?
|
84
98
|
flags << "C" if closed?
|
85
99
|
flags << "L" unless work_log.empty?
|
@@ -87,14 +101,30 @@ module Gwtf
|
|
87
101
|
flags
|
88
102
|
end
|
89
103
|
|
104
|
+
def colorize_by_due_date(string)
|
105
|
+
if overdue?
|
106
|
+
return Gwtf.red(string)
|
107
|
+
elsif days_till_due <= 1 && open?
|
108
|
+
return Gwtf.yellow(string)
|
109
|
+
else
|
110
|
+
return string
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
90
114
|
def summary
|
91
115
|
summary = StringIO.new
|
92
116
|
|
93
117
|
summary.puts " Subject: %s" % [ subject ]
|
94
118
|
summary.puts " Status: %s" % [ status ]
|
119
|
+
|
120
|
+
if has_due_date? && open?
|
121
|
+
due = "%s (%d days)" % [ due_date, days_till_due ]
|
122
|
+
summary.puts " Due Date: %s" % [ colorize_by_due_date(due) ]
|
123
|
+
end
|
124
|
+
|
95
125
|
summary.puts "Time Worked: %s" % [ Gwtf.seconds_to_human(time_worked) ]
|
96
|
-
summary.puts " Created: %s" % [ Time.parse(created_at).strftime("%F %R") ]
|
97
|
-
summary.puts " Closed: %s" % [ Time.parse(closed_at).strftime("%F %R") ] if closed?
|
126
|
+
summary.puts " Created: %s" % [ Time.parse(created_at.to_s).strftime("%F %R") ]
|
127
|
+
summary.puts " Closed: %s" % [ Time.parse(closed_at.to_s).strftime("%F %R") ] if closed?
|
98
128
|
summary.puts " ID: %s" % [ item_id ]
|
99
129
|
|
100
130
|
if has_description?
|
@@ -124,17 +154,13 @@ module Gwtf
|
|
124
154
|
end
|
125
155
|
|
126
156
|
def to_s
|
127
|
-
"%5s %-4s%-
|
128
|
-
end
|
129
|
-
|
130
|
-
def to_hash
|
131
|
-
@item
|
157
|
+
colorize_by_due_date("%5s %-4s%-10s %s" % [ item_id, compact_flags.join, has_due_date? ? due_date : "", subject ])
|
132
158
|
end
|
133
159
|
|
134
160
|
def record_work(text, elapsed=0)
|
135
161
|
update_property(:edited_at, Time.now)
|
136
162
|
|
137
|
-
|
163
|
+
work_log << {"text" => text, "time" => Time.now, "elapsed" => elapsed}
|
138
164
|
end
|
139
165
|
|
140
166
|
def open
|
@@ -147,35 +173,6 @@ module Gwtf
|
|
147
173
|
update_property(:status, "closed")
|
148
174
|
end
|
149
175
|
|
150
|
-
def to_json
|
151
|
-
JSON.pretty_generate(@item)
|
152
|
-
end
|
153
|
-
|
154
|
-
def to_yaml
|
155
|
-
@item.to_yaml
|
156
|
-
end
|
157
|
-
|
158
|
-
def update_property(property, value)
|
159
|
-
property = property.to_s
|
160
|
-
|
161
|
-
raise "No such property: #{property}" unless @item.include?(property)
|
162
|
-
|
163
|
-
@item["edited_at"] = Time.now
|
164
|
-
@item[property] = value
|
165
|
-
end
|
166
|
-
|
167
|
-
def [](property)
|
168
|
-
property = property.to_s
|
169
|
-
|
170
|
-
raise "No such property: #{property}" unless @item.include?(property)
|
171
|
-
|
172
|
-
@item[property]
|
173
|
-
end
|
174
|
-
|
175
|
-
def []=(property, value)
|
176
|
-
update_property(property, value)
|
177
|
-
end
|
178
|
-
|
179
176
|
def schedule_reminer(timespec, recipient, done=false, ifopen=false)
|
180
177
|
command_args = ["--send"]
|
181
178
|
command_args << "--recipient=%s" % [ recipient ]
|
@@ -194,54 +191,5 @@ module Gwtf
|
|
194
191
|
save
|
195
192
|
end
|
196
193
|
end
|
197
|
-
|
198
|
-
# simple read from the class:
|
199
|
-
#
|
200
|
-
# >> i.description
|
201
|
-
# => "Sample Item"
|
202
|
-
#
|
203
|
-
# method like writes:
|
204
|
-
#
|
205
|
-
# >> i.description "This is a test"
|
206
|
-
# => "This is a test"
|
207
|
-
#
|
208
|
-
# assignment
|
209
|
-
#
|
210
|
-
# >> i.description = "This is a test"
|
211
|
-
# => "This is a test"
|
212
|
-
#
|
213
|
-
# boolean
|
214
|
-
#
|
215
|
-
# >> i.description?
|
216
|
-
# => false
|
217
|
-
# >> i.description "foo"
|
218
|
-
# => foo
|
219
|
-
# >> i.has_description?
|
220
|
-
# => true
|
221
|
-
# >> i.has_description
|
222
|
-
# => true
|
223
|
-
def method_missing(method, *args)
|
224
|
-
method = method.to_s
|
225
|
-
|
226
|
-
if @item.include?(method)
|
227
|
-
if args.empty?
|
228
|
-
return @item[method]
|
229
|
-
else
|
230
|
-
return update_property(method, args.first)
|
231
|
-
end
|
232
|
-
|
233
|
-
elsif method =~ /^has_(.+?)\?*$/
|
234
|
-
return !@item[$1].nil?
|
235
|
-
|
236
|
-
elsif method =~ /^(.+)\?$/
|
237
|
-
return !@item[$1].nil?
|
238
|
-
|
239
|
-
elsif method =~ /^(.+)=$/
|
240
|
-
property = $1
|
241
|
-
return update_property(property, args.first) if @item.include?(property)
|
242
|
-
end
|
243
|
-
|
244
|
-
raise NameError, "undefined local variable or method `#{method}'"
|
245
|
-
end
|
246
194
|
end
|
247
195
|
end
|
data/lib/gwtf/items.rb
CHANGED
@@ -79,10 +79,14 @@ module Gwtf
|
|
79
79
|
|
80
80
|
# Returns an array of total, open and closed items for the current project
|
81
81
|
def stats
|
82
|
-
count = {"open" => 0, "closed" => 0}
|
82
|
+
count = {"open" => 0, "closed" => 0, "overdue" => 0, "due_soon" => 0, "due_today" => 0}
|
83
83
|
|
84
84
|
each_item do |item|
|
85
85
|
count[ item.status ] += 1
|
86
|
+
|
87
|
+
count["overdue"] += 1 if item.overdue?
|
88
|
+
count["due_soon"] += 1 if item.days_till_due == 1
|
89
|
+
count["due_today"] += 1 if item.days_till_due == 0
|
86
90
|
end
|
87
91
|
|
88
92
|
count["total"] = count["open"] + count["closed"]
|
@@ -110,7 +114,6 @@ module Gwtf
|
|
110
114
|
list.puts "Project %s items: %d / %d" % [ @project, count["open"], count["total"] ]
|
111
115
|
list.puts
|
112
116
|
list.puts items.string
|
113
|
-
list.puts
|
114
117
|
|
115
118
|
list.string
|
116
119
|
end
|
data/lib/gwtf/version.rb
CHANGED
data/lib/gwtf.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module Gwtf
|
2
|
+
require 'objhash'
|
2
3
|
require 'gwtf/items'
|
3
4
|
require 'gwtf/item'
|
4
5
|
require 'gwtf/version'
|
@@ -56,6 +57,30 @@ module Gwtf
|
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
60
|
+
def self.green(msg)
|
61
|
+
if STDOUT.tty?
|
62
|
+
"[1m[32m%s[0m" % [ msg ]
|
63
|
+
else
|
64
|
+
msg
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.yellow(msg)
|
69
|
+
if STDOUT.tty?
|
70
|
+
"[1m[33m%s[0m" % [ msg ]
|
71
|
+
else
|
72
|
+
msg
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.red(msg)
|
77
|
+
if STDOUT.tty?
|
78
|
+
"[1m[31m%s[0m" % [ msg ]
|
79
|
+
else
|
80
|
+
msg
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
59
84
|
# borrowed from ohai, thanks Adam.
|
60
85
|
def self.seconds_to_human(seconds)
|
61
86
|
days = seconds.to_i / 86400
|
data/lib/objhash.rb
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
module ObjHash
|
2
|
+
include Enumerable
|
3
|
+
|
4
|
+
module ClassMethods
|
5
|
+
# Create a new known property of the ObjHash
|
6
|
+
# it's imagined these might have validators, defaults
|
7
|
+
# required etc associated with them in args
|
8
|
+
def property(name, args={:default => nil, :validation => nil})
|
9
|
+
name = name.to_s
|
10
|
+
|
11
|
+
raise "Already have a property #{name}" if objhash_config.include?(name)
|
12
|
+
|
13
|
+
objhash_config[name] = {:default => nil, :validation => nil}.merge(args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def objhash_config
|
17
|
+
@objhash_values ||= {
|
18
|
+
"created_at" => {:default => lambda { Time.now }},
|
19
|
+
"edited_at" => {:default => lambda { Time.now }}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def objhash_default_value(property)
|
24
|
+
property = property.to_s
|
25
|
+
|
26
|
+
raise "Unknown property #{property}" unless objhash_config.include?(property)
|
27
|
+
|
28
|
+
if objhash_config[property][:default].is_a?(Proc)
|
29
|
+
objhash_config[property][:default].call
|
30
|
+
else
|
31
|
+
objhash_config[property][:default]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.included(base)
|
37
|
+
base.extend ClassMethods
|
38
|
+
end
|
39
|
+
|
40
|
+
def default_property_value(property)
|
41
|
+
self.class.objhash_default_value(property)
|
42
|
+
end
|
43
|
+
|
44
|
+
def objhash_config
|
45
|
+
self.class.objhash_config
|
46
|
+
end
|
47
|
+
|
48
|
+
def objhash_values
|
49
|
+
return @objhash_values if @objhash_values
|
50
|
+
|
51
|
+
@objhash_values = {}
|
52
|
+
|
53
|
+
objhash_config.each_pair do |property, args|
|
54
|
+
update_property(property, default_property_value(property))
|
55
|
+
end
|
56
|
+
|
57
|
+
@objhash_values
|
58
|
+
end
|
59
|
+
|
60
|
+
def include?(property)
|
61
|
+
objhash_config.include?(property.to_s)
|
62
|
+
end
|
63
|
+
|
64
|
+
def update_property(property, value)
|
65
|
+
property = property.to_s
|
66
|
+
|
67
|
+
raise "Unknown property #{property}" unless include?(property)
|
68
|
+
|
69
|
+
validate_property(property, value)
|
70
|
+
|
71
|
+
objhash_values[property] = value
|
72
|
+
objhash_values["edited_at"] = Time.now
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate_property(property, value)
|
76
|
+
raise "Unknown property #{property}" unless include?(property)
|
77
|
+
|
78
|
+
validation = objhash_config[property.to_s][:validation]
|
79
|
+
|
80
|
+
return true if validation.nil?
|
81
|
+
|
82
|
+
# if the value is the default we dont validate it allowing nil
|
83
|
+
# defaults but validation only on assignment of non default value
|
84
|
+
return true if value == objhash_config[property.to_s][:default]
|
85
|
+
|
86
|
+
raise "#{property} should be #{validation}" if value.nil? && !validation.nil?
|
87
|
+
|
88
|
+
if validation.is_a?(Symbol)
|
89
|
+
case validation
|
90
|
+
when :boolean
|
91
|
+
raise "#{property} should be a boolean" unless [TrueClass, FalseClass].include?(value.class)
|
92
|
+
when :ipv6
|
93
|
+
begin
|
94
|
+
require 'ipaddr'
|
95
|
+
ip = IPAddr.new(value)
|
96
|
+
raise "#{property} should be a valid IPv6 address" unless ip.ipv6?
|
97
|
+
rescue
|
98
|
+
raise "#{property} should be a valid IPv6 address"
|
99
|
+
end
|
100
|
+
|
101
|
+
when :ipv4
|
102
|
+
begin
|
103
|
+
require 'ipaddr'
|
104
|
+
ip = IPAddr.new(value)
|
105
|
+
raise "#{property} should be a valid IPv4 address" unless ip.ipv4?
|
106
|
+
rescue
|
107
|
+
raise "#{property} should be a valid IPv4 address"
|
108
|
+
end
|
109
|
+
else
|
110
|
+
raise "Don't know how to validate #{property} using #{validation}"
|
111
|
+
end
|
112
|
+
|
113
|
+
elsif validation.is_a?(Array)
|
114
|
+
raise "%s should be one of %s" % [property, validation.join(", ")] unless validation.include?(value)
|
115
|
+
|
116
|
+
elsif validation.is_a?(Regexp)
|
117
|
+
raise "#{property} should match #{validation}" unless value.match(validation)
|
118
|
+
|
119
|
+
elsif validation.is_a?(Proc)
|
120
|
+
raise "#{property} does not validate against lambda" unless validation.call(value)
|
121
|
+
|
122
|
+
else
|
123
|
+
raise "#{property} is a #{value.class} should be a #{validation}" unless value.is_a?(validation)
|
124
|
+
end
|
125
|
+
|
126
|
+
return true
|
127
|
+
end
|
128
|
+
|
129
|
+
def to_hash
|
130
|
+
objhash_values
|
131
|
+
end
|
132
|
+
|
133
|
+
def to_s
|
134
|
+
objhash_values.inspect
|
135
|
+
end
|
136
|
+
|
137
|
+
def to_json
|
138
|
+
objhash_values.to_json
|
139
|
+
end
|
140
|
+
|
141
|
+
def to_yaml
|
142
|
+
objhash_values.to_yaml
|
143
|
+
end
|
144
|
+
|
145
|
+
def each
|
146
|
+
objhash_values.keys.sort.each do |property|
|
147
|
+
yield [property, objhash_values[property]]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def [](property)
|
152
|
+
raise "No such property: #{property}" unless include?(property)
|
153
|
+
|
154
|
+
objhash_values[property.to_s]
|
155
|
+
end
|
156
|
+
|
157
|
+
def []=(property, value)
|
158
|
+
update_property(property, value)
|
159
|
+
end
|
160
|
+
|
161
|
+
def merge(hsh)
|
162
|
+
objhash_values.merge(hsh)
|
163
|
+
end
|
164
|
+
|
165
|
+
def merge!(hsh)
|
166
|
+
raise TypeError, "Can't convert #{hsh.class} into Hash" unless hsh.respond_to?(:to_hash)
|
167
|
+
|
168
|
+
objhash_values.keys.each do |k|
|
169
|
+
next if ["edited_at", "created_at"].include?(k)
|
170
|
+
update_property(k, hsh[k]) if hsh.include?(k)
|
171
|
+
end
|
172
|
+
|
173
|
+
self
|
174
|
+
end
|
175
|
+
|
176
|
+
# simple read from the class:
|
177
|
+
#
|
178
|
+
# >> i.description
|
179
|
+
# => "Sample Item"
|
180
|
+
#
|
181
|
+
# method like writes:
|
182
|
+
#
|
183
|
+
# >> i.description "This is a test"
|
184
|
+
# => "This is a test"
|
185
|
+
#
|
186
|
+
# assignment
|
187
|
+
#
|
188
|
+
# >> i.description = "This is a test"
|
189
|
+
# => "This is a test"
|
190
|
+
#
|
191
|
+
# boolean
|
192
|
+
#
|
193
|
+
# >> i.description?
|
194
|
+
# => false
|
195
|
+
# >> i.description "foo"
|
196
|
+
# => foo
|
197
|
+
# >> i.has_description?
|
198
|
+
# => true
|
199
|
+
# >> i.has_description
|
200
|
+
# => true
|
201
|
+
def method_missing(method, *args)
|
202
|
+
method = method.to_s
|
203
|
+
|
204
|
+
if include?(method)
|
205
|
+
if args.empty?
|
206
|
+
return objhash_values[method]
|
207
|
+
else
|
208
|
+
return update_property(method, args.first)
|
209
|
+
end
|
210
|
+
|
211
|
+
elsif method =~ /^(has_)*(.+?)\?$/
|
212
|
+
return !!objhash_values[$2]
|
213
|
+
|
214
|
+
elsif method =~ /^(.+)=$/
|
215
|
+
property = $1
|
216
|
+
return update_property(property, args.first) if include?(property)
|
217
|
+
end
|
218
|
+
|
219
|
+
raise NameError, "undefined local variable or method `#{method}'"
|
220
|
+
end
|
221
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gwtf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.4.
|
9
|
+
- 5
|
10
|
+
version: 0.4.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- R.I.Pienaar
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-04-
|
18
|
+
date: 2012-04-07 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -102,6 +102,7 @@ extra_rdoc_files: []
|
|
102
102
|
|
103
103
|
files:
|
104
104
|
- bin/gwtf
|
105
|
+
- lib/objhash.rb
|
105
106
|
- lib/gwtf/commands/show_command.rb
|
106
107
|
- lib/gwtf/commands/open_command.rb
|
107
108
|
- lib/gwtf/commands/shell_command.rb
|