termtter 1.7.2 → 1.8.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.
Files changed (81) hide show
  1. data/.gitignore +1 -1
  2. data/README.rdoc +1 -0
  3. data/Rakefile +2 -1
  4. data/VERSION +1 -1
  5. data/bin/termtter +1 -0
  6. data/bin/termtter_frame +134 -0
  7. data/lib/plugins/aa.rb +44 -0
  8. data/lib/plugins/another_prompt.rb +42 -41
  9. data/lib/plugins/appendtitle.rb +82 -0
  10. data/lib/plugins/ar.rb +11 -8
  11. data/lib/plugins/async.rb +3 -2
  12. data/lib/plugins/capital_update.rb +12 -0
  13. data/lib/plugins/channel.rb +149 -0
  14. data/lib/plugins/clock.rb +10 -0
  15. data/lib/plugins/defaults/command_line.rb +8 -0
  16. data/lib/plugins/defaults/confirm.rb +1 -1
  17. data/lib/plugins/defaults/hashtag.rb +1 -1
  18. data/lib/plugins/defaults/keyword.rb +11 -0
  19. data/lib/plugins/defaults/list.rb +32 -6
  20. data/lib/plugins/defaults/standard_commands.rb +135 -52
  21. data/lib/plugins/defaults/standard_completion.rb +14 -0
  22. data/lib/plugins/defaults/stdout.rb +59 -27
  23. data/lib/plugins/defaults/user.rb +32 -0
  24. data/lib/plugins/draft.rb +9 -12
  25. data/lib/plugins/easy_post.rb +5 -0
  26. data/lib/plugins/event_invoked_at.rb +23 -0
  27. data/lib/plugins/expand-tinyurl.rb +13 -20
  28. data/lib/plugins/favotter.rb +9 -9
  29. data/lib/plugins/footer.rb +9 -12
  30. data/lib/plugins/friends.rb +0 -26
  31. data/lib/plugins/grass.rb +2 -4
  32. data/lib/plugins/growl.rb +47 -0
  33. data/lib/plugins/gyazo.rb +16 -18
  34. data/lib/plugins/hi.rb +31 -10
  35. data/lib/plugins/http_server.rb +3 -2
  36. data/lib/plugins/irc_gw.rb +71 -17
  37. data/lib/plugins/line.rb +10 -0
  38. data/lib/plugins/linefeed.rb +6 -1
  39. data/lib/plugins/list_switch.rb +76 -0
  40. data/lib/plugins/nop.rb +9 -0
  41. data/lib/plugins/notify-send.rb +1 -1
  42. data/lib/plugins/notify-send2.rb +25 -16
  43. data/lib/plugins/notify-send3.rb +16 -13
  44. data/lib/plugins/nuance.rb +29 -0
  45. data/lib/plugins/open_url.rb +1 -5
  46. data/lib/plugins/random.rb +2 -6
  47. data/lib/plugins/reply_sound.rb +33 -0
  48. data/lib/plugins/say.rb +2 -2
  49. data/lib/plugins/storage/sqlite3.rb +1 -1
  50. data/lib/plugins/story.rb +44 -0
  51. data/lib/plugins/tinyurl.rb +50 -29
  52. data/lib/plugins/translate_tweet.rb +38 -0
  53. data/lib/plugins/web.rb +27 -0
  54. data/lib/termtter.rb +8 -4
  55. data/lib/termtter/client.rb +17 -21
  56. data/lib/termtter/command.rb +35 -13
  57. data/lib/termtter/config.rb +13 -0
  58. data/lib/termtter/config_template.erb +3 -2
  59. data/lib/termtter/default_config.rb +2 -2
  60. data/lib/termtter/event.rb +69 -0
  61. data/lib/termtter/hook.rb +6 -1
  62. data/lib/termtter/hookable.rb +9 -1
  63. data/lib/termtter/httppool.rb +17 -9
  64. data/lib/termtter/optparse.rb +11 -1
  65. data/lib/termtter/rubytter_proxy.rb +21 -5
  66. data/spec/plugins/capital_update_spec.rb +9 -0
  67. data/spec/plugins/fib_spec.rb +2 -4
  68. data/spec/plugins/hi_spec.rb +9 -0
  69. data/spec/plugins/tinyurl_spec.rb +78 -0
  70. data/spec/termtter/client_spec.rb +5 -12
  71. data/spec/termtter/command_spec.rb +22 -10
  72. data/spec/termtter/config_spec.rb +23 -0
  73. data/spec/termtter/event_spec.rb +129 -0
  74. data/spec/termtter/optparse_spec.rb +2 -2
  75. data/spec/termtter/rubytter_proxy_spec.rb +1 -1
  76. metadata +39 -8
  77. data/bin/kill_termtter +0 -22
  78. data/lib/plugins/defaults/users.rb +0 -63
  79. data/lib/plugins/pause.rb +0 -3
  80. data/test/friends_timeline.json +0 -5
  81. data/test/search.json +0 -8
@@ -4,6 +4,20 @@ require 'set'
4
4
 
5
5
  module Termtter::Client
6
6
 
7
+ #
8
+ # completion for status ids
9
+ # (This is needed for some plugins)
10
+ #
11
+
12
+ public_storage[:status_ids] ||= Set.new
13
+
14
+ register_hook(:collect_status_ids, :point => :pre_filter) do |statuses, event|
15
+ statuses.each do |s|
16
+ public_storage[:status_ids].add(s.id)
17
+ public_storage[:status_ids].add(s.in_reply_to_status_id) if s.in_reply_to_status_id
18
+ end
19
+ end
20
+
7
21
  #
8
22
  # completion for user names
9
23
  #
@@ -10,7 +10,7 @@ config.plugins.stdout.set_default(
10
10
  [
11
11
  '<90><%=time%> [<%=status_id%>]</90> ',
12
12
  '<%= indent_text %>',
13
- '<<%=color%>><%=s.user.screen_name%>: <%=colorize_users(text)%></<%=color%>> ',
13
+ '<<%=color%>><%=s.user.screen_name%>: <%=text%></<%=color%>> ',
14
14
  '<90>',
15
15
  '<%=reply_to_status_id ? " (reply_to [#{reply_to_status_id}]) " : ""%>',
16
16
  '<%=retweeted_status_id ? " (retweet_to [#{retweeted_status_id}]) " : ""%>',
@@ -18,6 +18,8 @@ config.plugins.stdout.set_default(
18
18
  '</90>'
19
19
  ].join('')
20
20
  )
21
+ config.plugins.stdout.set_default(:sweets, %w[jugyo ujm sora_h lingr_termtter termtter hitode909 nanki sixeight])
22
+ config.plugins.stdout.set_default(:sweet_color, 'red')
21
23
  config.plugins.stdout.set_default(:time_format_today, '%H:%M:%S')
22
24
  config.plugins.stdout.set_default(:time_format_not_today, '%y/%m/%d %H:%M')
23
25
  config.plugins.stdout.set_default(:enable_pager, false)
@@ -28,6 +30,8 @@ config.plugins.stdout.set_default(:typable_id_prefix, '$')
28
30
  config.plugins.stdout.set_default(:show_reply_chain, true)
29
31
  config.plugins.stdout.set_default(:indent_format, %q("#{' ' * (indent - 1)} → "))
30
32
  config.plugins.stdout.set_default(:max_indent_level, 1)
33
+ config.plugins.stdout.set_default(
34
+ :screen_name_to_hash_proc, lambda { |screen_name| screen_name.to_i(36) })
31
35
 
32
36
  module Termtter
33
37
  class TypableIdGenerator
@@ -64,7 +68,8 @@ module Termtter
64
68
  @typable_id_generator = TypableIdGenerator.new(config.plugins.stdout.typable_ids)
65
69
 
66
70
  def self.data_to_typable_id(data)
67
- id = config.plugins.stdout.typable_id_prefix + @typable_id_generator.get_id(data)
71
+ id = config.plugins.stdout.typable_id_prefix +
72
+ @typable_id_generator.get_id(data)
68
73
  end
69
74
 
70
75
  def self.typable_id_to_data(id)
@@ -102,12 +107,14 @@ module Termtter
102
107
  output_text << status_line(s, time_format, event)
103
108
  end
104
109
 
105
- if config.plugins.stdout.enable_pager && ENV['LINES'] && statuses.size > ENV['LINES'].to_i
106
- file = Tempfile.new('termtter')
107
- file.print output_text
108
- file.close
109
- system "#{config.plugins.stdout.pager} #{file.path}"
110
- file.close(true)
110
+ if config.plugins.stdout.enable_pager &&
111
+ ENV['LINES'] &&
112
+ statuses.size > ENV['LINES'].to_i
113
+ file = Tempfile.new('termtter')
114
+ file.print output_text
115
+ file.close
116
+ system "#{config.plugins.stdout.pager} #{file.path}"
117
+ file.close(true)
111
118
  else
112
119
  print output_text
113
120
  end
@@ -116,7 +123,7 @@ module Termtter
116
123
  def status_line(s, time_format, event, indent = 0)
117
124
  return '' unless s
118
125
  text = TermColor.escape(s.text)
119
- color = config.plugins.stdout.colors[s.user.id.to_i % config.plugins.stdout.colors.size]
126
+ color = color_of_user(s.user)
120
127
  status_id = Termtter::Client.data_to_typable_id(s.id)
121
128
  reply_to_status_id =
122
129
  if s.in_reply_to_status_id
@@ -139,18 +146,25 @@ module Termtter
139
146
  when 'web' then 'web'
140
147
  end
141
148
 
149
+ text = colorize_users(text)
150
+ text = Client.get_hooks(:pre_coloring).inject(text) {|result, hook|
151
+ Termtter::Client.logger.debug "stdout status_line: call hook :pre_coloring #{hook.inspect}"
152
+ hook.call(result, event)
153
+ }
142
154
  indent_text = indent > 0 ? eval(config.plugins.stdout.indent_format) : ''
143
155
  erbed_text = ERB.new(config.plugins.stdout.timeline_format).result(binding)
144
-
145
- erbed_text = Client.get_hooks(:pre_coloring).inject(erbed_text){|result, hook| hook.call(result, event)}
146
-
156
+ erbed_text = Client.get_hooks(:pre_output).inject(erbed_text) {|result, hook|
157
+ Termtter::Client.logger.debug "stdout status_line: call hook :pre_output #{hook.inspect}"
158
+ hook.call(result, event)
159
+ }
147
160
  text = TermColor.unescape(TermColor.parse(erbed_text) + "\n")
148
161
  if config.plugins.stdout.show_reply_chain && s.in_reply_to_status_id
149
162
  indent += 1
150
163
  unless indent > config.plugins.stdout.max_indent_level
151
164
  begin
152
- status = Termtter::API.twitter.show(s.in_reply_to_status_id)
153
- text << status_line(status, time_format, event, indent)
165
+ if status = Termtter::API.twitter.cached_status(s.in_reply_to_status_id)
166
+ text << status_line(status, time_format, event, indent)
167
+ end
154
168
  rescue Rubytter::APIError
155
169
  end
156
170
  end
@@ -159,19 +173,35 @@ module Termtter
159
173
  end
160
174
 
161
175
  def colorize_users(text)
162
- text.gsub(/@(\w+)/) do |i|
163
- user = Termtter::API.twitter.cached_user($1)
164
- if user
165
- color = user_color(user)
166
- "<#{color}>#{i}</#{color}>"
167
- else
168
- i
169
- end
176
+ text.gsub(/@([0-9A-Za-z_]+)/) do |i|
177
+ color = color_of_screen_name($1)
178
+ "<#{color}>#{i}</#{color}>"
170
179
  end
171
180
  end
172
181
 
173
- def user_color(user)
174
- config.plugins.stdout.colors[user.id.to_i % config.plugins.stdout.colors.size]
182
+ def color_of_user(user)
183
+ color_of_screen_name(user.screen_name)
184
+ end
185
+
186
+ def color_of_screen_name(screen_name)
187
+ return color_of_screen_name_cache[screen_name] if
188
+ color_of_screen_name_cache.key?(screen_name)
189
+ num = screen_name_to_hash(screen_name)
190
+ color = config.plugins.stdout.instance_eval {
191
+ sweets.include?(screen_name) ?
192
+ sweet_color : colors[num % colors.size]
193
+ }
194
+ color_of_screen_name_cache[screen_name] = color
195
+ color_of_screen_name_cache[screen_name]
196
+ end
197
+
198
+ def screen_name_to_hash(screen_name)
199
+ config.plugins.stdout.screen_name_to_hash_proc.
200
+ call(screen_name)
201
+ end
202
+
203
+ def color_of_screen_name_cache
204
+ @color_of_screen_name_cache ||= {}
175
205
  end
176
206
  end
177
207
 
@@ -196,6 +226,8 @@ end
196
226
  # stdout.rb
197
227
  # output statuses to stdout
198
228
  # example config
199
- # config.plugins.stdout.colors = [:none, :red, :green, :yellow, :blue, :magenta, :cyan]
200
- # config.plugins.stdout.timeline_format = '<90><%=time%> [<%=status_id%>]</90> <<%=color%>><%=s.user.screen_name%>: <%=text%></<%=color%>> ' +
201
- # '<90><%=reply_to_status_id ? " (reply_to [#{reply_to_status_id}]) " : ""%><%=source%></90>'
229
+ # config.plugins.stdout.colors =
230
+ # [:none, :red, :green, :yellow, :blue, :magenta, :cyan]
231
+ # config.plugins.stdout.timeline_format =
232
+ # '<90><%=time%> [<%=status_id%>]</90> <<%=color%>><%=s.user.screen_name%>: <%=text%></<%=color%>> ' +
233
+ # '<90><%=reply_to_status_id ? " (reply_to [#{reply_to_status_id}]) " : ""%><%=source%></90>'
@@ -0,0 +1,32 @@
1
+ module Termtter::Client
2
+ register_command(
3
+ 'user show',
4
+ :aliases => [:p, :profile],
5
+ :help => ["user show USERNAME", "Show user's profile."]
6
+ ) do |arg|
7
+ user_name = arg.empty? ? config.user_name : arg
8
+ user = Termtter::API.twitter.user(user_name)
9
+ attrs = %w[ name screen_name url description profile_image_url location protected following
10
+ friends_count followers_count statuses_count favourites_count
11
+ id time_zone created_at utc_offset notifications
12
+ ]
13
+ label_width = attrs.map(&:size).max
14
+ attrs.each do |attr|
15
+ value = user.__send__(attr.to_sym)
16
+ puts "#{attr.gsub('_', ' ').rjust(label_width)}: #{value}"
17
+ end
18
+ end
19
+
20
+ class UserSearchEvent; attr_reader :query; def initialize(query); @query = query end; end
21
+
22
+ register_command(
23
+ 'user search',
24
+ :help => ["user search QUERY", "search users"]
25
+ ) do |arg|
26
+ search_option = config.user_search.option.empty? ? {} : config.user_search.option
27
+ users = Termtter::API.twitter.search_user(arg, search_option)
28
+ users.each do |user|
29
+ puts "@#{user.screen_name} (#{user.name}): #{user.description}"
30
+ end
31
+ end
32
+ end
data/lib/plugins/draft.rb CHANGED
@@ -34,22 +34,19 @@ module Termtter::Client
34
34
 
35
35
  register_command('draft exec') do |arg|
36
36
  index = get_draft_index(arg)
37
- if index
38
- command = public_storage[:drafts][index]
39
- if command
40
- puts "exec => \"#{command}\""
41
- execute(public_storage[:drafts][index])
42
- public_storage[:drafts].delete_at(index)
43
- end
44
- end
37
+ break unless index
38
+ command = public_storage[:drafts][index]
39
+ break unless command
40
+ puts "exec => \"#{command}\""
41
+ execute(public_storage[:drafts][index])
42
+ public_storage[:drafts].delete_at(index)
45
43
  end
46
44
 
47
45
  register_command('draft delete') do |arg|
48
46
  index = get_draft_index(arg)
49
- if index
50
- deleted = public_storage[:drafts].delete_at(index)
51
- puts "deleted => \"#{deleted}\"" if deleted
52
- end
47
+ break unless index
48
+ deleted = public_storage[:drafts].delete_at(index)
49
+ puts "deleted => \"#{deleted}\"" if deleted
53
50
  end
54
51
 
55
52
  register_command('draft clear') do |arg|
@@ -0,0 +1,5 @@
1
+ module Termtter::Client
2
+ register_hook(:easy_post, :point => :command_not_found) do |text|
3
+ execute("update #{text}")
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Termtter::Client
4
+
5
+ register_hook(
6
+ :name => :set_invoked_at,
7
+ :point => :pre_filter,
8
+ :exec_proc => lambda do |statuses, event|
9
+ event[:invoked_at] = Time.now
10
+ statuses
11
+ end
12
+ )
13
+
14
+ register_hook(
15
+ :name => :print_invoked_at,
16
+ :point => :post_filter,
17
+ :exec_proc => lambda do |statuses, event|
18
+ puts "event was invoked at #{event.invoked_at}."
19
+ statuses
20
+ end
21
+ )
22
+
23
+ end
@@ -1,30 +1,22 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  URL_SHORTTERS = [
4
- { :host => "tinyurl.com", :pattern => %r'(http://tinyurl\.com(/[\w/]+))' },
5
- { :host => "is.gd", :pattern => %r'(http://is\.gd(/[\w/]+))' },
6
- { :host => "bit.ly", :pattern => %r'(http://bit\.ly(/[\w/]+))' },
7
- { :host => "ff.im", :pattern => %r'(http://ff\.im(/[-\w/]+))'},
8
- { :host => "j.mp", :pattern => %r'(http://j\.mp(/[\w/]+))' },
9
- { :host => "goo.gl", :pattern => %r'(http://goo\.gl(/[\w/]+))' },
4
+ {:host => "tinyurl.com", :pattern => %r'(http://tinyurl\.com(/[\w/]+))'},
5
+ {:host => "is.gd", :pattern => %r'(http://is\.gd(/[\w/]+))'},
6
+ {:host => "bit.ly", :pattern => %r'(http://bit\.ly(/[\w/]+))'},
7
+ {:host => "ff.im", :pattern => %r'(http://ff\.im(/[-\w/]+))'},
8
+ {:host => "j.mp", :pattern => %r'(http://j\.mp(/[\w/]+))'},
9
+ {:host => "goo.gl", :pattern => %r'(http://goo\.gl(/[\w/]+))'},
10
+ {:host => "tr.im", :pattern => %r'(http://tr\.im(/[\w/]+))'},
11
+ {:host => "short.to", :pattern => %r'(http://short\.to(/[\w/]+))'},
12
+ {:host => "ow.ly", :pattern => %r'(http://ow\.ly(/[\w/]+))'},
13
+ {:host => "u.nu", :pattern => %r'(http://u\.nu(/[\w/]+))'},
14
+ {:host => "twurl.nl", :pattern => %r'(http://twurl\.nl(/\w+))'},
10
15
  ]
11
16
 
12
17
  config.plugins.expand_tinyurl.set_default(:shortters, [])
13
18
  config.plugins.expand_tinyurl.set_default(:skip_users, [])
14
19
 
15
- # for Ruby 1.8
16
- unless String.public_method_defined?(:force_encoding)
17
- class String
18
- def force_encoding(enc)
19
- self
20
- end
21
- end
22
-
23
- module Encoding
24
- UTF_8 = nil
25
- end
26
- end
27
-
28
20
  Termtter::Client::register_hook(
29
21
  :name => :expand_tinyurl,
30
22
  :point => :filter_for_output,
@@ -48,7 +40,8 @@ def expand_url(host, path)
48
40
  h.get(path, { 'User-Agent' => 'Mozilla' })
49
41
  end
50
42
  return nil unless res.code == "301" or res.code == "302"
51
- res['Location'].force_encoding(Encoding::UTF_8)
43
+ newurl = res['Location']
44
+ newurl.respond_to?(:force_encoding) ? newurl.force_encoding(Encoding::UTF_8) : newurl
52
45
  rescue Exception => e
53
46
  Termtter::Client.handle_error(e)
54
47
  nil
@@ -5,7 +5,6 @@ require 'nokogiri'
5
5
  require 'open-uri'
6
6
 
7
7
  module Termtter::Client
8
-
9
8
  public_storage[:favorited_ids] = {}
10
9
 
11
10
  class << self
@@ -28,11 +27,12 @@ module Termtter::Client
28
27
  end
29
28
 
30
29
  private
30
+
31
31
  def parse(url)
32
32
  doc = Nokogiri(open(url).read)
33
33
  doc.css('div.entry').map do |entry|
34
34
  id = entry['id'].gsub(/\Astatus_/, '')
35
- text = entry.css('span.status_text').first.content
35
+ text = CGI.unescapeHTML(entry.css('span.status_text').first.content)
36
36
  amount = entry.css('div.info span.favotters').first.content
37
37
  amount = amount.match(/(\d+)/)[1].to_i
38
38
  users = entry.css('div.info span.favotters img').map {|u| u['title'] }
@@ -53,13 +53,14 @@ module Termtter::Client
53
53
 
54
54
  help = ['favotter [USERNAME] [THRESHOLD]', 'Show info from favotter']
55
55
  register_command('favotter', :help => help) do |arg|
56
- target = if arg.empty?
56
+ target =
57
+ if arg.empty?
57
58
  config.user_name
58
- else
59
- args = arg.split
60
- threshold = args.size == 1 ? 1 : args[1]
61
- args[0]
62
- end
59
+ else
60
+ args = arg.split
61
+ threshold = args.size == 1 ? 1 : args[1]
62
+ args[0]
63
+ end
63
64
  if /@(.*)/ =~ target
64
65
  target = $1
65
66
  end
@@ -74,4 +75,3 @@ module Termtter::Client
74
75
  end
75
76
  end
76
77
  end
77
-
@@ -1,22 +1,19 @@
1
1
  #-*- coding: utf-8 -*-
2
-
3
- config.set_default('footer',nil)
2
+ config.set_default('footer', nil)
4
3
 
5
4
  Termtter::Client.register_hook(
6
5
  :name => :add_footer,
7
6
  :points => [:modify_arg_for_update, :modify_arg_for_reply],
8
- :exec => lambda {|cmd, arg|
9
- (config.footer.nil? || config.footer.empty?) ? arg : arg + " #{config.footer}"
10
- }
11
- )
7
+ :exec => lambda {|cmd, arg|
8
+ (config.footer.nil? || config.footer.empty?) ?
9
+ arg : arg + " #{config.footer}"
10
+ })
12
11
 
13
12
  Termtter::Client.register_command(
14
13
  :name => :footer,
15
14
  :aliases => [:ft],
16
15
  :exec => lambda {|arg|
17
- arg.empty? ? config.footer = nil : config.footer = arg
18
- puts config.footer.nil? ? "footer is turned off" : "new footer=> #{config.footer}"
19
- }
20
- )
21
-
22
-
16
+ arg.empty? ? config.footer = nil : config.footer = arg
17
+ puts config.footer.nil? ?
18
+ "footer is turned off" : "new footer=> #{config.footer}"
19
+ })
@@ -1,31 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  module Termtter::Client
3
-
4
- class << self
5
- def get_friends(user_name, max)
6
- friends = []
7
- cursor = -1
8
- begin
9
- tmp = Termtter::API::twitter.friends(user_name, :cursor => cursor)
10
- cursor = tmp[:next_cursor]
11
- friends += tmp[:users]
12
- puts "#{friends.length}/#{max}"
13
- rescue
14
- end until (cursor.zero? or friends.length > max)
15
- friends.take(max)
16
- end
17
- end
18
-
19
- register_command(
20
- :name => :friends, :aliases => [:following],
21
- :exec_proc => lambda {|arg|
22
- user_name = arg.empty? ? config.user_name : arg
23
- public_storage[:friends] = friends = get_friends(user_name, 2000)
24
- puts friends.map(&:screen_name).join(' ')
25
- },
26
- :help => ["friends,following [USERNAME]", "Show user's friends."]
27
- )
28
-
29
3
  register_command(
30
4
  :name => :diff_follow, :aliases => [:diff],
31
5
  :exec_proc => lambda {|arg|
data/lib/plugins/grass.rb CHANGED
@@ -1,21 +1,19 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  module Termtter
3
3
  module Client
4
-
5
4
  config.plugins.grass.set_default(:rate, 0)
6
5
 
7
6
  register_command(
8
7
  :name => :w, :aliases => [:grass],
9
8
  :exec_proc => lambda {|arg|
10
9
  arg, rate = arg.split(/ /)
11
- count = arg =~ /^[0-9]+$/ ? arg.to_i : 3
10
+ count = /^[0-9]+$/ =~ arg ? arg.to_i : 3
12
11
  rate ||= config.plugins.grass.rate
13
12
  grow = (count * rate.to_i).quo(100).round
14
13
  grasses = ('w' * (count-grow) + 'W' * grow).split(//).shuffle.join
15
14
  execute("update #{grasses}")
16
15
  },
17
- :help => ['grass, w', 'Grass it!']
18
- )
16
+ :help => ['grass, w', 'Grass it!'])
19
17
  end
20
18
  end
21
19