cups 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/cups.c +457 -0
- data/ext/extconf.rb +15 -0
- data/ext/ruby_cups.h +10 -0
- data/test/cups_test.rb +121 -0
- data/test/sample.txt +9 -0
- data/test/sample_blank.txt +0 -0
- metadata +61 -0
data/ext/cups.c
ADDED
@@ -0,0 +1,457 @@
|
|
1
|
+
#include <ruby_cups.h>
|
2
|
+
|
3
|
+
static int num_options;
|
4
|
+
static cups_option_t *options;
|
5
|
+
cups_dest_t *dests, *dest;
|
6
|
+
VALUE rubyCups, printJobs;
|
7
|
+
|
8
|
+
|
9
|
+
/*
|
10
|
+
* call-seq:
|
11
|
+
* PrintJob.new(filename, printer=nil)
|
12
|
+
*
|
13
|
+
* Initializes a new PrintJob object. If no target printer/class is specified, the default is chosen.
|
14
|
+
* Note the specified file does not have to exist until print is called.
|
15
|
+
*/
|
16
|
+
static VALUE job_init(int argc, VALUE* argv, VALUE self)
|
17
|
+
{
|
18
|
+
VALUE filename, printer;
|
19
|
+
|
20
|
+
rb_scan_args(argc, argv, "11", &filename, &printer);
|
21
|
+
|
22
|
+
rb_iv_set(self, "@filename", filename);
|
23
|
+
|
24
|
+
if (NIL_P(printer)) {
|
25
|
+
|
26
|
+
// Fall back to default printer
|
27
|
+
VALUE def_p = rb_funcall(rubyCups, rb_intern("default_printer"), 0);
|
28
|
+
rb_iv_set(self, "@printer", def_p);
|
29
|
+
|
30
|
+
} else {
|
31
|
+
// First call Cups#show_destinations
|
32
|
+
VALUE dest_list = rb_funcall(rubyCups, rb_intern("show_destinations"), 0);
|
33
|
+
// Then check the printer arg is included in the returned array...
|
34
|
+
if (rb_ary_includes(dest_list, printer)) {
|
35
|
+
rb_iv_set(self, "@printer", printer);
|
36
|
+
} else {
|
37
|
+
rb_raise(rb_eRuntimeError, "The printer or destination doesn't exist!");
|
38
|
+
}
|
39
|
+
}
|
40
|
+
return self;
|
41
|
+
}
|
42
|
+
|
43
|
+
/*
|
44
|
+
* call-seq:
|
45
|
+
* print_job.print -> Fixnum
|
46
|
+
*
|
47
|
+
* Submit a print job to the selected printer or class. Returns true on success.
|
48
|
+
*/
|
49
|
+
static VALUE cups_print(VALUE self, VALUE file, VALUE printer)
|
50
|
+
{
|
51
|
+
int job_id;
|
52
|
+
file = rb_iv_get(self, "@filename");
|
53
|
+
printer = rb_iv_get(self, "@printer");
|
54
|
+
|
55
|
+
char *fname = RSTRING_PTR(file); // Filename
|
56
|
+
char *target = RSTRING_PTR(printer); // Target printer string
|
57
|
+
|
58
|
+
FILE *fp = fopen(fname,"r");
|
59
|
+
// Check @filename actually exists...
|
60
|
+
if( fp ) {
|
61
|
+
fclose(fp);
|
62
|
+
job_id = cupsPrintFile(target, fname, "rCUPS", num_options, options); // Do it.
|
63
|
+
rb_iv_set(self, "@job_id", INT2NUM(job_id));
|
64
|
+
return Qtrue;
|
65
|
+
} else {
|
66
|
+
// and if it doesn't...
|
67
|
+
rb_raise(rb_eRuntimeError, "Couldn't find file");
|
68
|
+
return self;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
/*
|
73
|
+
* call-seq:
|
74
|
+
* Cups.show_destinations -> Array
|
75
|
+
*
|
76
|
+
* Show all destinations on the default server
|
77
|
+
*/
|
78
|
+
static VALUE cups_show_dests(VALUE self)
|
79
|
+
{
|
80
|
+
VALUE dest_list;
|
81
|
+
int i;
|
82
|
+
int num_dests = cupsGetDests(&dests); // Size of dest_list array
|
83
|
+
dest_list = rb_ary_new2(num_dests);
|
84
|
+
|
85
|
+
for (i = num_dests, dest = dests; i > 0; i --, dest ++) {
|
86
|
+
VALUE destination = rb_str_new2(dest->name);
|
87
|
+
rb_ary_push(dest_list, destination); // Add this testination name to dest_list string
|
88
|
+
}
|
89
|
+
return dest_list;
|
90
|
+
}
|
91
|
+
|
92
|
+
/*
|
93
|
+
* call-seq:
|
94
|
+
* Cups.default_printer -> String or nil
|
95
|
+
*
|
96
|
+
* Get default printer or class. Returns a string or false if there is no default
|
97
|
+
*/
|
98
|
+
static VALUE cups_get_default(VALUE self)
|
99
|
+
{
|
100
|
+
const char *default_printer;
|
101
|
+
default_printer = cupsGetDefault();
|
102
|
+
|
103
|
+
if (default_printer != NULL) {
|
104
|
+
VALUE def_p = rb_str_new2(default_printer);
|
105
|
+
return def_p;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
/*
|
110
|
+
* call-seq:
|
111
|
+
* print_job.cancel -> true or false
|
112
|
+
*
|
113
|
+
* Cancel the current job. Returns true if successful, false otherwise.
|
114
|
+
*/
|
115
|
+
static VALUE cups_cancel(VALUE self)
|
116
|
+
{
|
117
|
+
VALUE printer, job_id;
|
118
|
+
printer = rb_iv_get(self, "@printer");
|
119
|
+
job_id = rb_iv_get(self, "@job_id");
|
120
|
+
|
121
|
+
if (NIL_P(job_id)) {
|
122
|
+
return Qfalse; // If @job_id is nil
|
123
|
+
} else { // Otherwise attempt to cancel
|
124
|
+
int job = NUM2INT(job_id);
|
125
|
+
char *target = RSTRING_PTR(printer); // Target printer string
|
126
|
+
int cancellation;
|
127
|
+
cancellation = cupsCancelJob(target, job);
|
128
|
+
return Qtrue;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
/*
|
133
|
+
* call-seq:
|
134
|
+
* print_job.failed? -> true or false
|
135
|
+
*
|
136
|
+
* Did this job fail?
|
137
|
+
*/
|
138
|
+
static VALUE cups_job_failed(VALUE self)
|
139
|
+
{
|
140
|
+
VALUE job_id = rb_iv_get(self, "@job_id");
|
141
|
+
|
142
|
+
if (NIL_P(job_id) || !NUM2INT(job_id) == 0) {
|
143
|
+
return Qfalse;
|
144
|
+
} else {
|
145
|
+
return Qtrue;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
/*
|
150
|
+
* call-seq:
|
151
|
+
* print_job.error_reason -> String
|
152
|
+
*
|
153
|
+
* Get the last human-readable error string
|
154
|
+
*/
|
155
|
+
static VALUE cups_get_error_reason(VALUE self)
|
156
|
+
{
|
157
|
+
VALUE job_id = rb_iv_get(self, "@job_id");
|
158
|
+
|
159
|
+
if (NIL_P(job_id) || !NUM2INT(job_id) == 0) {
|
160
|
+
return Qnil;
|
161
|
+
} else {
|
162
|
+
VALUE error_exp = rb_str_new2(cupsLastErrorString());
|
163
|
+
return error_exp;
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
/*
|
168
|
+
* call-seq:
|
169
|
+
* print_job.error_code -> Fixnum
|
170
|
+
*
|
171
|
+
* Get the last IPP error code.
|
172
|
+
*/
|
173
|
+
static VALUE cups_get_error_code(VALUE self)
|
174
|
+
{
|
175
|
+
VALUE job_id = rb_iv_get(self, "@job_id");
|
176
|
+
|
177
|
+
if (NIL_P(job_id) || !NUM2INT(job_id) == 0) {
|
178
|
+
return Qnil;
|
179
|
+
} else {
|
180
|
+
VALUE ipp_error_code = INT2NUM(cupsLastError());
|
181
|
+
return ipp_error_code;
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
/*
|
186
|
+
* call-seq:
|
187
|
+
* print_job.state -> String
|
188
|
+
*
|
189
|
+
* Get human-readable state of current job.
|
190
|
+
*/
|
191
|
+
static VALUE cups_get_job_state(VALUE self)
|
192
|
+
{
|
193
|
+
VALUE job_id = rb_iv_get(self, "@job_id");
|
194
|
+
VALUE printer = rb_iv_get(self, "@printer");
|
195
|
+
VALUE jstate;
|
196
|
+
|
197
|
+
int num_jobs;
|
198
|
+
cups_job_t *jobs;
|
199
|
+
ipp_jstate_t job_state = IPP_JOB_PENDING;
|
200
|
+
int i;
|
201
|
+
char *printer_arg = RSTRING_PTR(printer);
|
202
|
+
|
203
|
+
if (NIL_P(job_id)) {
|
204
|
+
return Qnil;
|
205
|
+
} else {
|
206
|
+
num_jobs = cupsGetJobs(&jobs, printer_arg, 1, -1); // Get jobs
|
207
|
+
|
208
|
+
for (i = 0; i < num_jobs; i ++) {
|
209
|
+
if (jobs[i].id == NUM2INT(job_id)) {
|
210
|
+
job_state = jobs[i].state;
|
211
|
+
break;
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
// Free job array
|
216
|
+
cupsFreeJobs(num_jobs, jobs);
|
217
|
+
|
218
|
+
switch (job_state) {
|
219
|
+
case IPP_JOB_PENDING :
|
220
|
+
jstate = rb_str_new2("Pending...");
|
221
|
+
break;
|
222
|
+
case IPP_JOB_HELD :
|
223
|
+
jstate = rb_str_new2("Held");
|
224
|
+
break;
|
225
|
+
case IPP_JOB_PROCESSING :
|
226
|
+
jstate = rb_str_new2("Processing...");
|
227
|
+
break;
|
228
|
+
case IPP_JOB_STOPPED :
|
229
|
+
jstate = rb_str_new2("Stopped");
|
230
|
+
break;
|
231
|
+
case IPP_JOB_CANCELED :
|
232
|
+
jstate = rb_str_new2("Cancelled");
|
233
|
+
break;
|
234
|
+
case IPP_JOB_ABORTED :
|
235
|
+
jstate = rb_str_new2("Aborted");
|
236
|
+
break;
|
237
|
+
case IPP_JOB_COMPLETED :
|
238
|
+
jstate = rb_str_new2("Completed");
|
239
|
+
break;
|
240
|
+
default:
|
241
|
+
jstate = rb_str_new2("Unknown Job Code...");
|
242
|
+
}
|
243
|
+
|
244
|
+
return jstate;
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
/*
|
249
|
+
* call-seq:
|
250
|
+
* print_job.completed? -> true or false
|
251
|
+
*
|
252
|
+
* Has the job completed?
|
253
|
+
*/
|
254
|
+
static VALUE cups_job_completed(VALUE self)
|
255
|
+
{
|
256
|
+
VALUE job_id = rb_iv_get(self, "@job_id");
|
257
|
+
VALUE printer = rb_iv_get(self, "@printer");
|
258
|
+
VALUE jstate;
|
259
|
+
|
260
|
+
int num_jobs;
|
261
|
+
cups_job_t *jobs;
|
262
|
+
ipp_jstate_t job_state = IPP_JOB_PENDING;
|
263
|
+
int i;
|
264
|
+
char *printer_arg = RSTRING_PTR(printer);
|
265
|
+
|
266
|
+
if (NIL_P(job_id)) {
|
267
|
+
return Qfalse;
|
268
|
+
} else {
|
269
|
+
num_jobs = cupsGetJobs(&jobs, printer_arg, 1, -1); // Get jobs
|
270
|
+
// job_state = IPP_JOB_COMPLETED;
|
271
|
+
|
272
|
+
for (i = 0; i < num_jobs; i ++) {
|
273
|
+
if (jobs[i].id == NUM2INT(job_id)) {
|
274
|
+
job_state = jobs[i].state;
|
275
|
+
break;
|
276
|
+
}
|
277
|
+
|
278
|
+
// Free job array
|
279
|
+
cupsFreeJobs(num_jobs, jobs);
|
280
|
+
|
281
|
+
if (job_state == IPP_JOB_COMPLETED) {
|
282
|
+
return Qtrue;
|
283
|
+
} else {
|
284
|
+
return Qfalse;
|
285
|
+
}
|
286
|
+
|
287
|
+
}
|
288
|
+
}
|
289
|
+
}
|
290
|
+
|
291
|
+
/*
|
292
|
+
* call-seq:
|
293
|
+
* Cups.all_jobs(printer) -> Hash
|
294
|
+
*
|
295
|
+
* Get all jobs from default CUPS server. Takes a single printer/class string argument.
|
296
|
+
* Returned hash keys are CUPS job ids, and the values are arrays of job info in the
|
297
|
+
* following order:
|
298
|
+
*
|
299
|
+
* [title,submitted_by,size,format,state]
|
300
|
+
*/
|
301
|
+
static VALUE cups_get_jobs(VALUE self, VALUE printer)
|
302
|
+
{
|
303
|
+
VALUE job_list, job_info_ary, jid, jtitle, juser, jsize, jformat, jstate;
|
304
|
+
int job_id;
|
305
|
+
int num_jobs;
|
306
|
+
cups_job_t *jobs;
|
307
|
+
ipp_jstate_t state;
|
308
|
+
int i;
|
309
|
+
char *printer_arg = RSTRING_PTR(printer);
|
310
|
+
|
311
|
+
num_jobs = cupsGetJobs(&jobs, printer_arg, 1, -1); // Get jobs
|
312
|
+
job_list = rb_hash_new();
|
313
|
+
|
314
|
+
for (i = 0; i < num_jobs; i ++) { // Construct a hash of individual job info
|
315
|
+
job_info_ary = rb_ary_new();
|
316
|
+
jid = INT2NUM(jobs[i].id);
|
317
|
+
jtitle = rb_str_new2(jobs[i].title);
|
318
|
+
juser = rb_str_new2(jobs[i].user);
|
319
|
+
jsize = INT2NUM(jobs[i].size);
|
320
|
+
jformat = rb_str_new2(jobs[i].format);
|
321
|
+
|
322
|
+
// Let's elaborate on that job state...
|
323
|
+
switch (jobs[i].state) {
|
324
|
+
case IPP_JOB_PENDING :
|
325
|
+
jstate = rb_str_new2("Pending...");
|
326
|
+
break;
|
327
|
+
case IPP_JOB_HELD :
|
328
|
+
jstate = rb_str_new2("Held");
|
329
|
+
break;
|
330
|
+
case IPP_JOB_PROCESSING :
|
331
|
+
jstate = rb_str_new2("Processing...");
|
332
|
+
break;
|
333
|
+
case IPP_JOB_STOPPED :
|
334
|
+
jstate = rb_str_new2("Stopped");
|
335
|
+
break;
|
336
|
+
case IPP_JOB_CANCELED :
|
337
|
+
jstate = rb_str_new2("Cancelled");
|
338
|
+
break;
|
339
|
+
case IPP_JOB_ABORTED :
|
340
|
+
jstate = rb_str_new2("Aborted");
|
341
|
+
break;
|
342
|
+
case IPP_JOB_COMPLETED :
|
343
|
+
jstate = rb_str_new2("Completed");
|
344
|
+
}
|
345
|
+
|
346
|
+
rb_ary_push(job_info_ary, jtitle);
|
347
|
+
rb_ary_push(job_info_ary, juser);
|
348
|
+
rb_ary_push(job_info_ary, jsize);
|
349
|
+
rb_ary_push(job_info_ary, jformat);
|
350
|
+
rb_ary_push(job_info_ary, jstate);
|
351
|
+
|
352
|
+
rb_hash_aset(job_list, jid, job_info_ary); // And push it all into job_list hash
|
353
|
+
}
|
354
|
+
|
355
|
+
// Free job array
|
356
|
+
cupsFreeJobs(num_jobs, jobs);
|
357
|
+
|
358
|
+
return job_list;
|
359
|
+
}
|
360
|
+
|
361
|
+
/*
|
362
|
+
* call-seq:
|
363
|
+
* Cups.options_for(name) -> Hash or nil
|
364
|
+
*
|
365
|
+
* Get all options from CUPS server with name. Returns a hash with key/value pairs
|
366
|
+
* based on server options, or nil if no server with name.
|
367
|
+
*/
|
368
|
+
static VALUE cups_get_options(VALUE self, VALUE printer)
|
369
|
+
{
|
370
|
+
VALUE options_list;
|
371
|
+
int i;
|
372
|
+
char *printer_arg = RSTRING_PTR(printer);
|
373
|
+
|
374
|
+
options_list = rb_hash_new();
|
375
|
+
|
376
|
+
cups_dest_t *dests;
|
377
|
+
int num_dests = cupsGetDests(&dests);
|
378
|
+
cups_dest_t *dest = cupsGetDest(printer_arg, NULL, num_dests, dests);
|
379
|
+
|
380
|
+
if (dest == NULL) {
|
381
|
+
cupsFreeDests(num_dests, dests);
|
382
|
+
return Qnil;
|
383
|
+
} else {
|
384
|
+
for(i =0; i< dest->num_options; i++) {
|
385
|
+
rb_hash_aset(options_list, rb_str_new2(dest->options[i].name), rb_str_new2(dest->options[i].value));
|
386
|
+
}
|
387
|
+
|
388
|
+
cupsFreeDests(num_dests, dests);
|
389
|
+
return options_list;
|
390
|
+
}
|
391
|
+
|
392
|
+
}
|
393
|
+
|
394
|
+
// TODO
|
395
|
+
// int ipp_state_to_string(int state)
|
396
|
+
// {
|
397
|
+
// // char *jstate;
|
398
|
+
// switch (state) {
|
399
|
+
// case IPP_JOB_PENDING :
|
400
|
+
// // jstate = rb_str_new2("Pending...");
|
401
|
+
// // char jstate[] = "Pending...";
|
402
|
+
// break;
|
403
|
+
// case IPP_JOB_HELD :
|
404
|
+
// // jstate = rb_str_new2("Held");
|
405
|
+
// // char jstate[] = "Held";
|
406
|
+
// break;
|
407
|
+
// case IPP_JOB_PROCESSING :
|
408
|
+
// // jstate = rb_str_new2("Processing...");
|
409
|
+
// // char jstate[] = "Processing...";
|
410
|
+
// break;
|
411
|
+
// case IPP_JOB_STOPPED :
|
412
|
+
// // jstate = rb_str_new2("Stopped");
|
413
|
+
// // char jstate[] = "Stopped";
|
414
|
+
// break;
|
415
|
+
// case IPP_JOB_CANCELED :
|
416
|
+
// // jstate = rb_str_new2("Cancelled");
|
417
|
+
// // char jstate[] = "Cancelled";
|
418
|
+
// break;
|
419
|
+
// case IPP_JOB_ABORTED :
|
420
|
+
// // jstate = rb_str_new2("Aborted");
|
421
|
+
// // char jstate[] = "Aborted";
|
422
|
+
// break;
|
423
|
+
// case IPP_JOB_COMPLETED :
|
424
|
+
// // jstate = rb_str_new2("Completed");
|
425
|
+
// break;
|
426
|
+
// }
|
427
|
+
// return 0;
|
428
|
+
// }
|
429
|
+
|
430
|
+
/*
|
431
|
+
*/
|
432
|
+
|
433
|
+
void Init_cups() {
|
434
|
+
rubyCups = rb_define_module("Cups");
|
435
|
+
printJobs = rb_define_class_under(rubyCups, "PrintJob", rb_cObject);
|
436
|
+
|
437
|
+
// Cups::PrintJob Attributes
|
438
|
+
rb_define_attr(printJobs, "printer", 1, 0);
|
439
|
+
rb_define_attr(printJobs, "filename", 1, 0);
|
440
|
+
rb_define_attr(printJobs, "job_id", 1, 0);
|
441
|
+
|
442
|
+
// Cups::PrintJob Methods
|
443
|
+
rb_define_method(printJobs, "initialize", job_init, -1);
|
444
|
+
rb_define_method(printJobs, "print", cups_print, 0);
|
445
|
+
rb_define_method(printJobs, "cancel", cups_cancel, 0);
|
446
|
+
rb_define_method(printJobs, "state", cups_get_job_state, 0);
|
447
|
+
rb_define_method(printJobs, "completed?", cups_job_completed, 0);
|
448
|
+
rb_define_method(printJobs, "failed?", cups_job_failed, 0);
|
449
|
+
rb_define_method(printJobs, "error_reason", cups_get_error_reason, 0);
|
450
|
+
rb_define_method(printJobs, "error_code", cups_get_error_code, 0);
|
451
|
+
|
452
|
+
// Cups Module Methods
|
453
|
+
rb_define_singleton_method(rubyCups, "show_destinations", cups_show_dests, 0);
|
454
|
+
rb_define_singleton_method(rubyCups, "default_printer", cups_get_default, 0);
|
455
|
+
rb_define_singleton_method(rubyCups, "all_jobs", cups_get_jobs, 1);
|
456
|
+
rb_define_singleton_method(rubyCups, "options_for", cups_get_options, 1);
|
457
|
+
}
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "mkmf"
|
2
|
+
|
3
|
+
unless have_library("cups") && find_executable("cups-config")
|
4
|
+
puts "Couldn't find CUPS libraries on your system. Check they're installed and in your path."
|
5
|
+
exit
|
6
|
+
end
|
7
|
+
|
8
|
+
cups_cflags = `cups-config --cflags`.chomp || ""
|
9
|
+
cups_libs = `cups-config --libs`.chomp || ""
|
10
|
+
|
11
|
+
with_cflags(cups_cflags) {
|
12
|
+
with_ldflags(cups_libs) {
|
13
|
+
create_makefile("cups")
|
14
|
+
}
|
15
|
+
}
|
data/ext/ruby_cups.h
ADDED
data/test/cups_test.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
require "cups"
|
2
|
+
require "test/unit"
|
3
|
+
|
4
|
+
# The tests which don't make use of mocking go on the operating assumption that you have
|
5
|
+
# the CUPS command line utilities installed and in your $PATH
|
6
|
+
|
7
|
+
class CupsTest < Test::Unit::TestCase
|
8
|
+
def test_same_printers_returned
|
9
|
+
lplist = `lpstat -a`.split("\n").map { |pr| pr.split(' ').first }
|
10
|
+
cups_destinations = Cups.show_destinations
|
11
|
+
assert cups_destinations.is_a?(Array)
|
12
|
+
assert_equal cups_destinations, lplist
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_can_instantiate_print_job_object_with_correct_args
|
16
|
+
assert_raise(ArgumentError) do
|
17
|
+
Cups::PrintJob.new
|
18
|
+
end
|
19
|
+
|
20
|
+
assert_nothing_raised do
|
21
|
+
Cups::PrintJob.new("/path", "PDF_Printer")
|
22
|
+
Cups::PrintJob.new("/path")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_job_defaults_to_default
|
27
|
+
assert_nothing_raised do
|
28
|
+
pj = Cups::PrintJob.new("/non/existent/file")
|
29
|
+
|
30
|
+
assert_equal Cups.default_printer, pj.instance_variable_get(:@printer)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_we_cant_print_to_nonexistent_printers
|
35
|
+
assert_raise(RuntimeError) do
|
36
|
+
pj = Cups::PrintJob.new("/non/existent/file", "bollocks_printer")
|
37
|
+
|
38
|
+
assert !Cups.show_destinations.include?(pj.instance_variable_get(:@printer))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_we_cant_print_nonexistent_files
|
43
|
+
pj = Cups::PrintJob.new("soft_class")
|
44
|
+
|
45
|
+
assert_raise(RuntimeError) do
|
46
|
+
pj.print
|
47
|
+
end
|
48
|
+
|
49
|
+
assert_nil pj.job_id
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_print_job_cancellation
|
53
|
+
pj = Cups::PrintJob.new(sample, "soft_class")
|
54
|
+
pj.print
|
55
|
+
assert_not_nil pj.job_id
|
56
|
+
assert_equal pj.cancel, true
|
57
|
+
assert pj.job_id.is_a?(Fixnum)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_all_jobs_returns_hash
|
61
|
+
assert Cups.all_jobs(Cups.default_printer).is_a?(Hash)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_dest_list_returns_array
|
65
|
+
assert Cups.show_destinations.is_a?(Array)
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_dest_options_returns_hash_if_real
|
69
|
+
assert Cups.options_for("PDF_Printer").is_a?(Hash)
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_dest_options_returns_nil_if_not_real
|
73
|
+
assert_nil Cups.options_for("bollocks_printer")
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_job_failed_boolean
|
77
|
+
pj = Cups::PrintJob.new(sample, "soft_class")
|
78
|
+
pj.print
|
79
|
+
pj.cancel
|
80
|
+
assert !pj.failed?
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_returns_failure_string_on_cancellation
|
84
|
+
pj = Cups::PrintJob.new(blank_sample, "PDF_Printer")
|
85
|
+
pj.print
|
86
|
+
|
87
|
+
assert pj.job_id == 0 # Failed jobs have an ID of zero
|
88
|
+
assert pj.failed?
|
89
|
+
|
90
|
+
assert pj.error_reason.is_a?(String)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_job_state_string
|
94
|
+
pj = Cups::PrintJob.new(sample, "soft_class")
|
95
|
+
assert_nil pj.state # A job can't have a state if it hasn't been assigned a job_id yet
|
96
|
+
assert !pj.completed?
|
97
|
+
|
98
|
+
pj.print
|
99
|
+
|
100
|
+
pj.cancel
|
101
|
+
assert pj.state == "Cancelled"
|
102
|
+
assert !pj.completed?
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_print_job_attributes
|
106
|
+
pj = Cups::PrintJob.new(sample)
|
107
|
+
[:printer, :filename, :job_id].each do |attr|
|
108
|
+
assert pj.respond_to?(attr)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def sample
|
115
|
+
"#{Dir.pwd}/sample.txt"
|
116
|
+
end
|
117
|
+
|
118
|
+
def blank_sample
|
119
|
+
"#{Dir.pwd}/sample_blank.txt"
|
120
|
+
end
|
121
|
+
end
|
data/test/sample.txt
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris rutrum, nibh ut hendrerit luctus, nisl risus ultrices lorem, sed luctus ipsum velit eget ante. Vestibulum eget est. Sed lectus odio, eleifend non, iaculis in, varius ut, sapien. Suspendisse suscipit urna in sem. Cras in mauris. Sed sapien urna, semper vitae, vulputate a, venenatis et, lacus. Praesent tristique turpis quis quam. Nullam a velit a erat imperdiet luctus. Cras vulputate dignissim leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut nulla lorem, dictum quis, cursus eu, dictum ac, nisi.
|
2
|
+
|
3
|
+
Pellentesque posuere commodo nunc. Sed eu turpis ac neque cursus aliquet. Nullam semper turpis. In sit amet metus. Nunc vel diam. Praesent sit amet ipsum varius dolor pulvinar pellentesque. Nullam hendrerit. Curabitur condimentum luctus nisi. Morbi eu erat vel eros aliquam sagittis. Sed pellentesque hendrerit augue. Pellentesque facilisis, dui at placerat vulputate, odio metus pulvinar metus, ac porta metus nibh a tortor. Cras lorem dolor, ornare quis, tempor quis, faucibus ut, metus. Donec ac ipsum. Sed pretium.
|
4
|
+
|
5
|
+
Praesent elementum dapibus sapien. Nam eleifend faucibus felis. Aliquam erat volutpat. In egestas, ipsum non rutrum cursus, ante libero hendrerit enim, ut lobortis nibh ligula sit amet enim. Nullam dui nulla, ullamcorper et, posuere ac, hendrerit vel, ligula. Suspendisse vel urna non nibh ultrices congue. Sed neque. Sed id tellus eget turpis aliquet mollis. Suspendisse sed eros. Vivamus nulla. Maecenas pulvinar. Aliquam sodales blandit mi.
|
6
|
+
|
7
|
+
Curabitur lacinia. Mauris vehicula enim at odio. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque augue sapien, faucibus et, pulvinar vel, tempor eget, elit. Cras a leo vitae justo aliquam laoreet. In et orci sed leo scelerisque condimentum. Integer scelerisque condimentum nisl. Aenean sit amet ligula. In fringilla. Nam elementum diam in dui.
|
8
|
+
|
9
|
+
Maecenas aliquam volutpat lectus. Vivamus tellus purus, scelerisque ac, suscipit sed, rhoncus id, justo. Quisque dolor sapien, accumsan vitae, dignissim sed, pulvinar nec, ligula. Cras ligula quam, iaculis ut, ultrices id, varius nec, neque. Mauris ornare nisl ac nunc. Maecenas interdum nisl et quam. Etiam purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nam sodales odio. Cras eu ipsum. Donec fringilla odio. Etiam vitae felis vitae lectus porttitor molestie. Nunc consectetur enim at elit tincidunt tempor. Ut fringilla, tortor in rutrum egestas, magna ante suscipit nunc, sit amet sagittis justo quam quis est. Nulla sit amet tortor nec ligula ultricies placerat. Cras congue quam in magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce a ante. Etiam congue nunc quis ligula. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
File without changes
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cups
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Mowforth
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-22 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: " Ruby CUPS provides a wrapper for the Common UNIX Printing System, allowing rubyists to perform basic tasks like printer discovery, job submission & querying.\n"
|
17
|
+
email:
|
18
|
+
- chris@mowforth.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions:
|
22
|
+
- ext/extconf.rb
|
23
|
+
extra_rdoc_files: []
|
24
|
+
|
25
|
+
files:
|
26
|
+
- test/cups_test.rb
|
27
|
+
- test/sample.txt
|
28
|
+
- test/sample_blank.txt
|
29
|
+
- ext/cups.c
|
30
|
+
- ext/ruby_cups.h
|
31
|
+
- ext/extconf.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://cups.rubyforge.org/
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project: cups
|
56
|
+
rubygems_version: 1.3.3
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: A lightweight Ruby library for printing.
|
60
|
+
test_files: []
|
61
|
+
|