Class: GemeraldBeanstalk::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/gemerald_beanstalk/command.rb

Constant Summary collapse

COMMAND_PARSER_REGEX =
/(?:(?<command>.*?)\r\n)(?<body>.*\r\n)?\z/m
TRAILING_SPACE_REGEX =
/\s+\z/
WHITE_SPACE_REGEX =
/ /
ZERO_STRING_REGEX =
/^0+[^1-9]*/
VALID_TUBE_NAME_REGEX =
/\A[a-zA-Z0-9_+\/;.$()]{1}[a-zA-Z0-9_\-+\/;.$()]*\z/
BAD_FORMAT =
GemeraldBeanstalk::Beanstalk::BAD_FORMAT
UNKNOWN_COMMAND =
GemeraldBeanstalk::Beanstalk::UNKNOWN_COMMAND
COMMANDS =
[
  :bury, :delete, :ignore, :kick, :'kick-job', :'list-tubes', :'list-tube-used', :'list-tubes-watched',
  :'pause-tube', :peek, :'peek-buried', :'peek-delayed', :'peek-ready', :put, :quit, :release, :reserve,
  :'reserve-with-timeout', :stats, :'stats-job', :'stats-tube', :touch, :use, :watch,
]
COMMAND_METHOD_NAMES =
Hash[COMMANDS.zip(COMMANDS)].merge!({
  :'kick-job' => 'kick_job', :'list-tubes' => 'list_tubes', :'list-tube-used' => 'list_tube_used',
  :'list-tubes-watched' => :'list_tubes_watched', :'pause-tube' => 'pause_tube', :'peek-buried' => 'peek_buried',
  :'peek-delayed' => 'peek_delayed', :'peek-ready' => 'peek_ready', :'reserve-with-timeout' => 'reserve_with_timeout',
  :'stats-job' => 'stats_job', :'stats-tube' => 'stats_tube',
})
COMMANDS_RECOGNIZED_WITHOUT_SPACE_AFTER_COMMAND =
[
  :'list-tubes', :'list-tube-used', :'list-tubes-watched', :'peek-buried', :'peek-delayed', :'peek-ready',
  :'pause-tube', :quit, :reserve, :'reserve-with-timeout', :stats, :'stats-job', :'stats-tube',
]
COMMANDS_REQUIRING_SPACE_AFTER_COMMAND =
COMMANDS - COMMANDS_RECOGNIZED_WITHOUT_SPACE_AFTER_COMMAND

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(raw_command, connection) ⇒ Command

Returns a new instance of Command.



46
47
48
49
# File 'lib/gemerald_beanstalk/command.rb', line 46

def initialize(raw_command, connection)
  @connection = connection
  parse(raw_command)
end

Instance Attribute Details

#bodyObject

Returns the value of attribute body.



34
35
36
# File 'lib/gemerald_beanstalk/command.rb', line 34

def body
  @body
end

#commandObject (readonly)

Returns the value of attribute command.



33
34
35
# File 'lib/gemerald_beanstalk/command.rb', line 33

def command
  @command
end

#connectionObject (readonly)

Returns the value of attribute connection.



33
34
35
# File 'lib/gemerald_beanstalk/command.rb', line 33

def connection
  @connection
end

#errorObject (readonly)

Returns the value of attribute error.



33
34
35
# File 'lib/gemerald_beanstalk/command.rb', line 33

def error
  @error
end

Instance Method Details

#argumentsObject



37
38
39
40
41
42
43
# File 'lib/gemerald_beanstalk/command.rb', line 37

def arguments
  if command == :put
    return @args[0, @argument_cardnality].unshift(connection).push(body)
  else
    return @args[0, @argument_cardnality].unshift(connection)
  end
end

#bad_format!Object (private)



73
74
75
# File 'lib/gemerald_beanstalk/command.rb', line 73

def bad_format!
  invalidate(BAD_FORMAT)
end

#buryObject (private)



78
79
80
81
82
83
84
# File 'lib/gemerald_beanstalk/command.rb', line 78

def bury
  @argument_cardnality = 2
  return requires_no_space_after_line &&
  requires_exact_argument_count &&
  requires_valid_integer(@args[0]) &&
  requires_valid_integer(@args[1], :positive => true)
end

#deleteObject (private)



87
88
89
90
# File 'lib/gemerald_beanstalk/command.rb', line 87

def delete
  @argument_cardnality = 1
  return true
end

#ignoreObject (private)



93
94
95
96
97
98
# File 'lib/gemerald_beanstalk/command.rb', line 93

def ignore
  @argument_cardnality = 1
  return requires_no_space_after_line &&
  requires_exact_argument_count &&
  requires_valid_tube_name(@args[0])
end

#invalidate(error) ⇒ Object (private)



101
102
103
104
# File 'lib/gemerald_beanstalk/command.rb', line 101

def invalidate(error)
  @error = error
  @value = false
end

#kickObject (private)



107
108
109
110
111
# File 'lib/gemerald_beanstalk/command.rb', line 107

def kick
  @argument_cardnality = 1
  return requires(@args[0]) &&
  requires_valid_integer(@args[0], :allow_trailing => true)
end

#kick_jobObject (private)



114
115
116
117
# File 'lib/gemerald_beanstalk/command.rb', line 114

def kick_job
  @argument_cardnality = 1
  return true
end

#list_tube_usedObject (private)



126
127
128
129
# File 'lib/gemerald_beanstalk/command.rb', line 126

def list_tube_used
  @argument_cardnality = 0
  return requires_only_command
end

#list_tubesObject (private)



120
121
122
123
# File 'lib/gemerald_beanstalk/command.rb', line 120

def list_tubes
  @argument_cardnality = 0
  return requires_only_command
end

#list_tubes_watchedObject (private)



132
133
134
135
# File 'lib/gemerald_beanstalk/command.rb', line 132

def list_tubes_watched
  @argument_cardnality = 0
  return requires_only_command
end

#method_nameObject



52
53
54
# File 'lib/gemerald_beanstalk/command.rb', line 52

def method_name
  return COMMAND_METHOD_NAMES[command]
end

#multi_part_request?Boolean

Returns:

  • (Boolean)


57
58
59
# File 'lib/gemerald_beanstalk/command.rb', line 57

def multi_part_request?
  return command == :put && body.nil?
end

#parse(raw_command) ⇒ Object (private)



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/gemerald_beanstalk/command.rb', line 138

def parse(raw_command)
  @command_lines = raw_command.match(COMMAND_PARSER_REGEX)
  if @command_lines.nil?
    return unknown_command!
  end

  @args = @command_lines[:command].split(WHITE_SPACE_REGEX)
  @command = @args.shift.to_sym rescue nil

  @space_after_command = @command && !!(raw_command[@command.length] =~ WHITE_SPACE_REGEX)
  @body = @command_lines[:body]

  return unknown_command! unless valid_command?

  return bad_format! unless send(method_name)
  @valid = true
end

#pause_tubeObject (private)



157
158
159
160
161
162
163
# File 'lib/gemerald_beanstalk/command.rb', line 157

def pause_tube
  @argument_cardnality = 2
  return requires_no_space_after_line &&
  requires(@args[0]) &&
  requires_valid_integer(@args[1]) &&
  requires_valid_tube_name(@args[0])
end

#peekObject (private)



166
167
168
169
# File 'lib/gemerald_beanstalk/command.rb', line 166

def peek
  @argument_cardnality = 1
  return true
end

#peek_buriedObject (private)



172
173
174
175
# File 'lib/gemerald_beanstalk/command.rb', line 172

def peek_buried
  @argument_cardnality = 0
  return requires_only_command
end

#peek_delayedObject (private)



178
179
180
181
# File 'lib/gemerald_beanstalk/command.rb', line 178

def peek_delayed
  @argument_cardnality = 0
  return requires_only_command
end

#peek_readyObject (private)



184
185
186
187
# File 'lib/gemerald_beanstalk/command.rb', line 184

def peek_ready
  @argument_cardnality = 0
  return requires_only_command
end

#putObject (private)



190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/gemerald_beanstalk/command.rb', line 190

def put
  @argument_cardnality = 5
  return false unless @args.all? do |arg|
    requires_valid_integer(arg, :positive => true)
  end

  # Handle weird case where BAD_FORMAT, but increments stats
  is_valid = requires_no_space_after_line
  unless is_valid
    connection.beanstalk.adjust_stats_cmd_put
  end
  return is_valid
end

#quitObject (private)



205
206
207
208
# File 'lib/gemerald_beanstalk/command.rb', line 205

def quit
  @argument_cardnality = 0
  return requires_only_command
end

#releaseObject (private)



211
212
213
214
215
216
217
218
# File 'lib/gemerald_beanstalk/command.rb', line 211

def release
  @argument_cardnality = 3
  return requires_no_space_after_line &&
  requires_exact_argument_count &&
  requires_valid_integer(@args[0]) &&
  requires_valid_integer(@args[1], :positive => true) &&
  requires_valid_integer(@args[2], :positive => true)
end

#requires(arg) ⇒ Object (private)



221
222
223
224
225
226
# File 'lib/gemerald_beanstalk/command.rb', line 221

def requires(arg)
  return true unless arg.nil?

  bad_format!
  return false
end

#requires_exact_argument_countObject (private)



229
230
231
232
233
234
# File 'lib/gemerald_beanstalk/command.rb', line 229

def requires_exact_argument_count
  return true if @args.length == @argument_cardnality

  bad_format!
  return false
end

#requires_no_space_after_commandObject (private)



237
238
239
240
241
242
# File 'lib/gemerald_beanstalk/command.rb', line 237

def requires_no_space_after_command
  return true unless @space_after_command

  bad_format!
  return false
end

#requires_no_space_after_lineObject (private)



245
246
247
248
249
250
# File 'lib/gemerald_beanstalk/command.rb', line 245

def requires_no_space_after_line
  return true unless @command_lines[:command] =~ TRAILING_SPACE_REGEX

  bad_format!
  return false
end

#requires_only_commandObject (private)



253
254
255
# File 'lib/gemerald_beanstalk/command.rb', line 253

def requires_only_command
  return requires_no_space_after_command && requires_exact_argument_count
end

#requires_space_after_commandObject (private)



258
259
260
261
262
263
# File 'lib/gemerald_beanstalk/command.rb', line 258

def requires_space_after_command
  return true if @space_after_command

  bad_format!
  return false
end

#requires_valid_integer(arg, opts = {}) ⇒ Object (private)



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/gemerald_beanstalk/command.rb', line 266

def requires_valid_integer(arg, opts = {})
  arg_to_i = arg.to_i
  if opts[:allow_trailing]
    if arg_to_i == 0 && arg !~ ZERO_STRING_REGEX
      bad_format!
      return false
    end
  else
    if arg_to_i.to_s != arg
      bad_format!
      return false
    end
  end

  return true if opts[:positive] ? arg_to_i >= 0 : true

  bad_format!
  return false
end

#requires_valid_tube_name(tube_name) ⇒ Object (private)



287
288
289
290
291
292
# File 'lib/gemerald_beanstalk/command.rb', line 287

def requires_valid_tube_name(tube_name)
  return true if valid_tube_name?(tube_name)

  bad_format!
  return false
end

#reserveObject (private)



295
296
297
298
# File 'lib/gemerald_beanstalk/command.rb', line 295

def reserve
  @argument_cardnality = 0
  return requires_only_command
end

#reserve_with_timeoutObject (private)



301
302
303
304
# File 'lib/gemerald_beanstalk/command.rb', line 301

def reserve_with_timeout
  @argument_cardnality = 1
  return requires_space_after_command
end

#statsObject (private)



307
308
309
310
# File 'lib/gemerald_beanstalk/command.rb', line 307

def stats
  @argument_cardnality = 0
  return requires_only_command
end

#stats_jobObject (private)



313
314
315
316
# File 'lib/gemerald_beanstalk/command.rb', line 313

def stats_job
  @argument_cardnality = 1
  return requires_space_after_command
end

#stats_tubeObject (private)



319
320
321
322
323
324
# File 'lib/gemerald_beanstalk/command.rb', line 319

def stats_tube
  @argument_cardnality = 1
  return requires_space_after_command &&
  requires_no_space_after_line &&
  requires_valid_tube_name(@args[0])
end

#to_sObject



62
63
64
# File 'lib/gemerald_beanstalk/command.rb', line 62

def to_s
  return "#{command} #{@args.join(' ')}"
end

#touchObject (private)



327
328
329
330
# File 'lib/gemerald_beanstalk/command.rb', line 327

def touch
  @argument_cardnality = 1
  return true
end

#unknown_command!Object (private)



341
342
343
# File 'lib/gemerald_beanstalk/command.rb', line 341

def unknown_command!
  invalidate(UNKNOWN_COMMAND)
end

#useObject (private)



333
334
335
336
337
338
# File 'lib/gemerald_beanstalk/command.rb', line 333

def use
  @argument_cardnality = 1
  return requires_no_space_after_line &&
  requires_exact_argument_count &&
  requires_valid_tube_name(@args[0])
end

#valid?Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/gemerald_beanstalk/command.rb', line 67

def valid?
  return @valid
end

#valid_command?Boolean (private)

Returns:

  • (Boolean)


346
347
348
349
350
# File 'lib/gemerald_beanstalk/command.rb', line 346

def valid_command?
  return COMMANDS_RECOGNIZED_WITHOUT_SPACE_AFTER_COMMAND.include?(command) || (
    COMMANDS_REQUIRING_SPACE_AFTER_COMMAND.include?(command) && @space_after_command
  )
end

#valid_tube_name?(tube_name) ⇒ Boolean (private)

Returns:

  • (Boolean)


353
354
355
# File 'lib/gemerald_beanstalk/command.rb', line 353

def valid_tube_name?(tube_name)
  return !tube_name.nil? && tube_name.bytesize <= 200 && VALID_TUBE_NAME_REGEX =~ tube_name
end

#watchObject (private)



358
359
360
361
362
363
# File 'lib/gemerald_beanstalk/command.rb', line 358

def watch
  @argument_cardnality = 1
  return requires_no_space_after_line &&
  requires_exact_argument_count &&
  requires_valid_tube_name(@args[0])
end