thorsson_cups 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/ext/cups.c ADDED
@@ -0,0 +1,480 @@
1
+ #include <ruby_cups.h>
2
+
3
+ cups_dest_t *dests, *dest;
4
+ VALUE rubyCups, printJobs;
5
+
6
+ // Need to abstract this out of cups.c
7
+ VALUE ipp_state_to_symbol(int state)
8
+ {
9
+
10
+ VALUE jstate;
11
+
12
+ switch (state) {
13
+ case IPP_JOB_PENDING :
14
+ jstate = ID2SYM(rb_intern("pending"));
15
+ break;
16
+ case IPP_JOB_HELD :
17
+ jstate = ID2SYM(rb_intern("held"));
18
+ break;
19
+ case IPP_JOB_PROCESSING :
20
+ jstate = ID2SYM(rb_intern("processing"));
21
+ break;
22
+ case IPP_JOB_STOPPED :
23
+ jstate = ID2SYM(rb_intern("stopped"));
24
+ break;
25
+ case IPP_JOB_CANCELED :
26
+ jstate = ID2SYM(rb_intern("cancelled"));
27
+ break;
28
+ case IPP_JOB_ABORTED :
29
+ jstate = ID2SYM(rb_intern("aborted"));
30
+ break;
31
+ case IPP_JOB_COMPLETED :
32
+ jstate = ID2SYM(rb_intern("completed"));
33
+ break;
34
+ default:
35
+ jstate = ID2SYM(rb_intern("unknown"));
36
+ }
37
+ return jstate;
38
+ }
39
+
40
+ int printer_exists(VALUE printer){
41
+ // First call Cups#show_destinations
42
+ VALUE dest_list = rb_funcall(rubyCups, rb_intern("show_destinations"), 0);
43
+ // Then check the printer arg is included in the returned array...
44
+ rb_ary_includes(dest_list, printer) ? 1 : 0;
45
+ }
46
+
47
+ /*
48
+ * call-seq:
49
+ * PrintJob.new(filename, printer=nil)
50
+ *
51
+ * Initializes a new PrintJob object. If no target printer/class is specified, the default is chosen.
52
+ * Note the specified file does not have to exist until print is called.
53
+ */
54
+ static VALUE job_init(int argc, VALUE* argv, VALUE self)
55
+ {
56
+ VALUE filename, printer, job_options;
57
+
58
+ rb_scan_args(argc, argv, "12", &filename, &printer, &job_options);
59
+
60
+ rb_iv_set(self, "@filename", filename);
61
+
62
+ if (NIL_P(job_options)) {
63
+ rb_iv_set(self, "@job_options", rb_hash_new());
64
+ } else {
65
+ rb_iv_set(self, "@job_options", job_options);
66
+ }
67
+
68
+ if (NIL_P(printer)) {
69
+
70
+ // Fall back to default printer
71
+ VALUE def_p = rb_funcall(rubyCups, rb_intern("default_printer"), 0);
72
+
73
+ if (def_p == Qfalse) {
74
+ rb_raise(rb_eRuntimeError, "There is no default printer!");
75
+ } else {
76
+ rb_iv_set(self, "@printer", def_p);
77
+ }
78
+
79
+ } else {
80
+ if (printer_exists(printer)) {
81
+ rb_iv_set(self, "@printer", printer);
82
+ } else {
83
+ rb_raise(rb_eRuntimeError, "The printer or destination doesn't exist!");
84
+ }
85
+ }
86
+ return self;
87
+ }
88
+
89
+ /*
90
+ * Note: rb_hash_keys is defined in 1.8.6, but not in 1.8.7 ubuntu shared lib
91
+ * This is so that I can get a list of keys to convert to options
92
+ */
93
+ static int
94
+ cups_keys_i(key, value, ary)
95
+ VALUE key, value, ary;
96
+ {
97
+ if (key == Qundef) return ST_CONTINUE;
98
+ rb_ary_push(ary, key);
99
+ return ST_CONTINUE;
100
+ }
101
+
102
+ /*
103
+ * call-seq:
104
+ * print_job.print -> Fixnum
105
+ *
106
+ * Submit a print job to the selected printer or class. Returns true on success.
107
+ */
108
+ static VALUE cups_print(VALUE self)
109
+ {
110
+ int job_id;
111
+ VALUE file = rb_iv_get(self, "@filename");
112
+ VALUE printer = rb_iv_get(self, "@printer");
113
+
114
+ char *fname = RSTRING_PTR(file); // Filename
115
+ char *target = RSTRING_PTR(printer); // Target printer string
116
+
117
+ FILE *fp = fopen(fname,"r");
118
+ // Check @filename actually exists...
119
+ if( fp ) {
120
+ fclose(fp);
121
+
122
+ VALUE job_options = rb_iv_get(self, "@job_options");
123
+
124
+ // Create an array of the keys from the job_options hash
125
+ VALUE job_options_keys = rb_ary_new();
126
+ rb_hash_foreach(job_options, cups_keys_i, job_options_keys);
127
+
128
+ VALUE iter;
129
+ int num_options = 0;
130
+ cups_option_t *options = NULL;
131
+
132
+ // foreach option in the job options array
133
+ while (! NIL_P(iter = rb_ary_pop(job_options_keys))) {
134
+
135
+ VALUE value = rb_hash_aref(job_options, iter);
136
+
137
+ // assert the key and value are strings
138
+ if (NIL_P(rb_check_string_type(iter)) || NIL_P(rb_check_string_type(value))) {
139
+ cupsFreeOptions(num_options, options);
140
+ rb_raise(rb_eTypeError, "job options is not string => string hash");
141
+ return Qfalse;
142
+ }
143
+
144
+ // convert to char pointers and add to cups optoins
145
+ char * iter_str = rb_string_value_ptr(&iter);
146
+ char * value_str = rb_string_value_ptr(&value);
147
+ cupsAddOption(iter_str, value_str, num_options++, &options);
148
+ }
149
+
150
+ job_id = cupsPrintFile(target, fname, "rCUPS", num_options, options); // Do it. "rCups" should be the filename/path
151
+
152
+ cupsFreeOptions(num_options, options);
153
+
154
+ rb_iv_set(self, "@job_id", INT2NUM(job_id));
155
+
156
+ return Qtrue;
157
+ } else {
158
+ // and if it doesn't...
159
+ rb_raise(rb_eRuntimeError, "Couldn't find file");
160
+ return Qfalse;
161
+ }
162
+ }
163
+
164
+ /*
165
+ * call-seq:
166
+ * Cups.show_destinations -> Array
167
+ *
168
+ * Show all destinations on the default server
169
+ */
170
+ static VALUE cups_show_dests(VALUE self)
171
+ {
172
+ VALUE dest_list;
173
+ int i;
174
+ int num_dests = cupsGetDests(&dests); // Size of dest_list array
175
+ dest_list = rb_ary_new2(num_dests);
176
+
177
+ for (i = num_dests, dest = dests; i > 0; i --, dest ++) {
178
+ VALUE destination = rb_str_new2(dest->name);
179
+ rb_ary_push(dest_list, destination); // Add this testination name to dest_list string
180
+ }
181
+ return dest_list;
182
+ }
183
+
184
+ /*
185
+ * call-seq:
186
+ * Cups.default_printer -> String or nil
187
+ *
188
+ * Get default printer or class. Returns a string or false if there is no default
189
+ */
190
+ static VALUE cups_get_default(VALUE self)
191
+ {
192
+ const char *default_printer;
193
+ default_printer = cupsGetDefault();
194
+
195
+ if (default_printer != NULL) {
196
+ VALUE def_p = rb_str_new2(default_printer);
197
+ return def_p;
198
+ }
199
+ // should return nil if no default printer is found!
200
+ }
201
+
202
+ /*
203
+ * call-seq:
204
+ * print_job.cancel -> true or false
205
+ *
206
+ * Cancel the current job. Returns true if successful, false otherwise.
207
+ */
208
+ static VALUE cups_cancel(VALUE self)
209
+ {
210
+ VALUE printer, job_id;
211
+ printer = rb_iv_get(self, "@printer");
212
+ job_id = rb_iv_get(self, "@job_id");
213
+
214
+ if (NIL_P(job_id)) {
215
+ return Qfalse; // If @job_id is nil
216
+ } else { // Otherwise attempt to cancel
217
+ int job = NUM2INT(job_id);
218
+ char *target = RSTRING_PTR(printer); // Target printer string
219
+ int cancellation;
220
+ cancellation = cupsCancelJob(target, job);
221
+ return Qtrue;
222
+ }
223
+ }
224
+
225
+ /*
226
+ * call-seq:
227
+ * print_job.failed? -> true or false
228
+ *
229
+ * Did this job fail?
230
+ */
231
+ static VALUE cups_job_failed(VALUE self)
232
+ {
233
+ VALUE job_id = rb_iv_get(self, "@job_id");
234
+
235
+ if (NIL_P(job_id) || !NUM2INT(job_id) == 0) {
236
+ return Qfalse;
237
+ } else {
238
+ return Qtrue;
239
+ }
240
+ }
241
+
242
+ /*
243
+ * call-seq:
244
+ * print_job.error_reason -> String
245
+ *
246
+ * Get the last human-readable error string
247
+ */
248
+ static VALUE cups_get_error_reason(VALUE self)
249
+ {
250
+ VALUE job_id = rb_iv_get(self, "@job_id");
251
+
252
+ if (NIL_P(job_id) || !NUM2INT(job_id) == 0) {
253
+ return Qnil;
254
+ } else {
255
+ VALUE error_exp = rb_str_new2(cupsLastErrorString());
256
+ return error_exp;
257
+ }
258
+ }
259
+
260
+ /*
261
+ * call-seq:
262
+ * print_job.error_code -> Fixnum
263
+ *
264
+ * Get the last IPP error code.
265
+ */
266
+ static VALUE cups_get_error_code(VALUE self)
267
+ {
268
+ VALUE job_id = rb_iv_get(self, "@job_id");
269
+
270
+ if (NIL_P(job_id) || !NUM2INT(job_id) == 0) {
271
+ return Qnil;
272
+ } else {
273
+ VALUE ipp_error_code = INT2NUM(cupsLastError());
274
+ return ipp_error_code;
275
+ }
276
+ }
277
+
278
+ /*
279
+ * call-seq:
280
+ * print_job.state -> String
281
+ *
282
+ * Get human-readable state of current job.
283
+ */
284
+ static VALUE cups_get_job_state(VALUE self)
285
+ {
286
+ VALUE job_id = rb_iv_get(self, "@job_id");
287
+ VALUE printer = rb_iv_get(self, "@printer");
288
+ VALUE jstate;
289
+
290
+ int num_jobs;
291
+ cups_job_t *jobs;
292
+ ipp_jstate_t job_state = IPP_JOB_PENDING;
293
+ int i;
294
+ char *printer_arg = RSTRING_PTR(printer);
295
+
296
+ if (NIL_P(job_id)) {
297
+ return Qnil;
298
+ } else {
299
+ num_jobs = cupsGetJobs(&jobs, printer_arg, 1, -1); // Get jobs
300
+
301
+ for (i = 0; i < num_jobs; i ++) {
302
+ if (jobs[i].id == NUM2INT(job_id)) {
303
+ job_state = jobs[i].state;
304
+ break;
305
+ }
306
+ }
307
+
308
+ // Free job array
309
+ cupsFreeJobs(num_jobs, jobs);
310
+
311
+ jstate = ipp_state_to_symbol(job_state);
312
+
313
+ return jstate;
314
+ }
315
+ }
316
+
317
+ /*
318
+ * call-seq:
319
+ * print_job.completed? -> true or false
320
+ *
321
+ * Has the job completed?
322
+ */
323
+ static VALUE cups_job_completed(VALUE self)
324
+ {
325
+ VALUE job_id = rb_iv_get(self, "@job_id");
326
+ VALUE printer = rb_iv_get(self, "@printer");
327
+ VALUE jstate;
328
+
329
+ int num_jobs;
330
+ cups_job_t *jobs;
331
+ ipp_jstate_t job_state = IPP_JOB_PENDING;
332
+ int i;
333
+ char *printer_arg = RSTRING_PTR(printer);
334
+
335
+ if (NIL_P(job_id)) {
336
+ return Qfalse;
337
+ } else {
338
+ num_jobs = cupsGetJobs(&jobs, printer_arg, 1, -1); // Get jobs
339
+ // job_state = IPP_JOB_COMPLETED;
340
+
341
+ for (i = 0; i < num_jobs; i ++) {
342
+ if (jobs[i].id == NUM2INT(job_id)) {
343
+ job_state = jobs[i].state;
344
+ break;
345
+ }
346
+
347
+ // Free job array
348
+ cupsFreeJobs(num_jobs, jobs);
349
+
350
+ if (job_state == IPP_JOB_COMPLETED) {
351
+ return Qtrue;
352
+ } else {
353
+ return Qfalse;
354
+ }
355
+
356
+ }
357
+ }
358
+ }
359
+
360
+ /*
361
+ * call-seq:
362
+ * Cups.all_jobs(printer) -> Hash
363
+ *
364
+ * Get all jobs from default CUPS server. Takes a single printer/class string argument.
365
+ * Returned hash keys are CUPS job ids, and the values are hashes of job info
366
+ * with keys:
367
+ *
368
+ * [:title, :submitted_by, :size, :format, :state]
369
+ */
370
+
371
+
372
+ static VALUE cups_get_jobs(VALUE self, VALUE printer)
373
+ {
374
+ // Don't have to lift a finger unless the printer exists.
375
+ if (!printer_exists(printer)){
376
+ rb_raise(rb_eRuntimeError, "The printer or destination doesn't exist!");
377
+ }
378
+
379
+ VALUE job_list, job_info_hash, jid, jtitle, juser, jsize, jformat, jstate;
380
+ int job_id;
381
+ int num_jobs;
382
+ cups_job_t *jobs;
383
+ ipp_jstate_t state;
384
+ int i;
385
+ char *printer_arg = RSTRING_PTR(printer);
386
+
387
+ num_jobs = cupsGetJobs(&jobs, printer_arg, 1, -1); // Get jobs
388
+ job_list = rb_hash_new();
389
+
390
+ for (i = 0; i < num_jobs; i ++) { // Construct a hash of individual job info
391
+ job_info_hash = rb_hash_new();
392
+ jid = INT2NUM(jobs[i].id);
393
+ jtitle = rb_str_new2(jobs[i].title);
394
+ juser = rb_str_new2(jobs[i].user);
395
+ jsize = INT2NUM(jobs[i].size);
396
+ jformat = rb_str_new2(jobs[i].format);
397
+ jstate = ipp_state_to_symbol(jobs[i].state);
398
+
399
+ rb_hash_aset(job_info_hash, ID2SYM(rb_intern("title")), jtitle);
400
+ rb_hash_aset(job_info_hash, ID2SYM(rb_intern("submitted_by")), juser);
401
+ rb_hash_aset(job_info_hash, ID2SYM(rb_intern("size")), jsize);
402
+ rb_hash_aset(job_info_hash, ID2SYM(rb_intern("format")), jformat);
403
+ rb_hash_aset(job_info_hash, ID2SYM(rb_intern("state")), jstate);
404
+
405
+ rb_hash_aset(job_list, jid, job_info_hash); // And push it all into job_list hash
406
+ }
407
+
408
+ // Free job array
409
+ cupsFreeJobs(num_jobs, jobs);
410
+
411
+ return job_list;
412
+ }
413
+
414
+ /*
415
+ * call-seq:
416
+ * Cups.options_for(name) -> Hash or nil
417
+ *
418
+ * Get all options from CUPS server with name. Returns a hash with key/value pairs
419
+ * based on server options, or nil if no server with name.
420
+ */
421
+ static VALUE cups_get_options(VALUE self, VALUE printer)
422
+ {
423
+ // Don't have to lift a finger unless the printer exists.
424
+ if (!printer_exists(printer)){
425
+ rb_raise(rb_eRuntimeError, "The printer or destination doesn't exist!");
426
+ }
427
+
428
+ VALUE options_list;
429
+ int i;
430
+ char *printer_arg = RSTRING_PTR(printer);
431
+
432
+ options_list = rb_hash_new();
433
+
434
+ cups_dest_t *dests;
435
+ int num_dests = cupsGetDests(&dests);
436
+ cups_dest_t *dest = cupsGetDest(printer_arg, NULL, num_dests, dests);
437
+
438
+ if (dest == NULL) {
439
+ cupsFreeDests(num_dests, dests);
440
+ return Qnil;
441
+ } else {
442
+ for(i =0; i< dest->num_options; i++) {
443
+ rb_hash_aset(options_list, rb_str_new2(dest->options[i].name), rb_str_new2(dest->options[i].value));
444
+ }
445
+
446
+ cupsFreeDests(num_dests, dests);
447
+ return options_list;
448
+ }
449
+
450
+ }
451
+
452
+ /*
453
+ */
454
+
455
+ void Init_cups() {
456
+ rubyCups = rb_define_module("Cups");
457
+ printJobs = rb_define_class_under(rubyCups, "PrintJob", rb_cObject);
458
+
459
+ // Cups::PrintJob Attributes
460
+ rb_define_attr(printJobs, "printer", 1, 0);
461
+ rb_define_attr(printJobs, "filename", 1, 0);
462
+ rb_define_attr(printJobs, "job_id", 1, 0);
463
+ rb_define_attr(printJobs, "job_options", 1, 0);
464
+
465
+ // Cups::PrintJob Methods
466
+ rb_define_method(printJobs, "initialize", job_init, -1);
467
+ rb_define_method(printJobs, "print", cups_print, 0);
468
+ rb_define_method(printJobs, "cancel", cups_cancel, 0);
469
+ rb_define_method(printJobs, "state", cups_get_job_state, 0);
470
+ rb_define_method(printJobs, "completed?", cups_job_completed, 0);
471
+ rb_define_method(printJobs, "failed?", cups_job_failed, 0);
472
+ rb_define_method(printJobs, "error_reason", cups_get_error_reason, 0);
473
+ rb_define_method(printJobs, "error_code", cups_get_error_code, 0);
474
+
475
+ // Cups Module Methods
476
+ rb_define_singleton_method(rubyCups, "show_destinations", cups_show_dests, 0);
477
+ rb_define_singleton_method(rubyCups, "default_printer", cups_get_default, 0);
478
+ rb_define_singleton_method(rubyCups, "all_jobs", cups_get_jobs, 1);
479
+ rb_define_singleton_method(rubyCups, "options_for", cups_get_options, 1);
480
+ }
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
@@ -0,0 +1,14 @@
1
+ #include <cups/cups.h>
2
+
3
+ // st.h is needed for ST_CONTINUE constant
4
+ #ifdef __APPLE__
5
+ #include <ruby/ruby.h>
6
+ #include <ruby/st.h>
7
+ #else
8
+ #include <ruby.h>
9
+ #include <st.h>
10
+ #endif
11
+
12
+ #ifndef MAXOPTS
13
+ #define MAXOPTS 100
14
+ #endif
@@ -0,0 +1,56 @@
1
+ require "cups"
2
+ require "tempfile"
3
+
4
+ module Cups
5
+
6
+ class PrintJob
7
+
8
+ # Unlike its superclass, a Transient object takes a string of data (e.g. from an IO object).
9
+ # This is useful when you've got something like a PDF, an ImageMagick byte array, etc that you
10
+ # just want to send on its way rather than having to touch the file system directly.
11
+ # === A contrived example:
12
+ # Say we're using Prawn[http://prawn.majesticseacreature.com/] to generate PDF invoices for some nebulous,
13
+ # ever-expanding system that promises us sex, drugs, rock & roll, fame and perhaps a pay-rise. Instead of just
14
+ # generating a file, let's pass the rendered version to a Transient object and let it take care of things:
15
+ #
16
+ # ---
17
+ #
18
+ # require 'cups/print_job/transient'
19
+ # require 'prawn'
20
+ #
21
+ # invoice = Prawn::Document.new do
22
+ # text "Invoice."
23
+ # end
24
+ #
25
+ # paper_copy = Cups::PrintJob::Transient.new(invoice.render)
26
+ # paper_copy.print
27
+ #
28
+ # ---
29
+ #
30
+ # As of 0.0.5, all instance methods inherited from PrintJob are unaltered. This may change if I need to
31
+ # delay passing the print data or change it after initialization, just as PrintJob currently permits the
32
+ # file to be written to/moved/nonexistent until print is called.
33
+ #
34
+ # Enjoy.
35
+
36
+ class Transient < PrintJob
37
+
38
+ alias_method :old_init, :initialize
39
+
40
+ # Create a print job from a non-empty string. Takes optional printer argument, otherwise uses default.
41
+ # As the tempfile is written to and closed upon initialization, an error will be raised if an empty
42
+ # string is passed as the first argument.
43
+ def initialize(data_string, printer=nil)
44
+ raise "Temporary print job has no data!" if data_string.empty?
45
+
46
+ file = Tempfile.new('')
47
+ file.puts(data_string)
48
+ file.close
49
+
50
+ old_init(file.path, printer)
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,35 @@
1
+ require "cups"
2
+
3
+ module Cups
4
+
5
+ # Right now this just wraps the Cups.options_for hash using method_missing, allowing you to call
6
+ # things like Printer#printer_make_and_model on an instance.
7
+ class Printer
8
+
9
+ # Creates a Cups::Printer object. Defaults to the default printer, if there is one.
10
+ def initialize(printer=nil)
11
+ if printer.nil?
12
+ raise "There is no default printer!" if !Cups.default_printer
13
+ @printer = Cups.default_printer
14
+ else
15
+ raise "The printer or destination doesn't exist!" unless Cups.show_destinations.include?(printer)
16
+ @printer = printer
17
+ end
18
+ end
19
+
20
+ # Call an options key on this object (with hyphens substituted with underscores). Passes onto super if
21
+ # no key is found or its value is nil.
22
+ def method_missing(m)
23
+ get_options
24
+ key = m.to_s.gsub(/\_/, "-")
25
+ @options[key].nil? ? super : @options[key]
26
+ end
27
+
28
+ private
29
+
30
+ def get_options
31
+ @options ||= Cups.options_for(@printer)
32
+ end
33
+
34
+ end
35
+ end
data/test/cups_test.rb ADDED
@@ -0,0 +1,159 @@
1
+ $LOAD_PATH.unshift File.expand_path( File.dirname(__FILE__) )
2
+
3
+ require 'rubygems'
4
+ require "cups"
5
+ require "test/unit"
6
+
7
+ # The tests which don't make use of mocking go on the operating assumption that you have
8
+ # the CUPS command line utilities installed and in your $PATH
9
+
10
+ class CupsTest < Test::Unit::TestCase
11
+
12
+ def setup
13
+ @printer = Cups.show_destinations.select {|p| p =~ /pdf/i}.first
14
+ raise "Can't find a PDF printer to run tests with." unless @printer
15
+ end
16
+
17
+ def test_same_printers_returned
18
+ lplist = `lpstat -a`.split("\n").map { |pr| pr.split(' ').first }
19
+ cups_destinations = Cups.show_destinations
20
+ assert cups_destinations.is_a?(Array)
21
+ assert_equal cups_destinations, lplist
22
+ end
23
+
24
+ def test_can_instantiate_print_job_object_with_correct_args
25
+ assert_raise(ArgumentError) do
26
+ Cups::PrintJob.new
27
+ end
28
+
29
+ assert_nothing_raised do
30
+ Cups::PrintJob.new("/path", @printer)
31
+ Cups::PrintJob.new("/path")
32
+ end
33
+ end
34
+
35
+ def test_job_defaults_to_default
36
+ assert_nothing_raised do
37
+ pj = Cups::PrintJob.new("/non/existent/file")
38
+
39
+ assert_equal Cups.default_printer, pj.instance_variable_get(:@printer)
40
+ end
41
+ end
42
+
43
+ def test_we_cant_print_to_nonexistent_printers
44
+ assert_raise(RuntimeError) do
45
+ pj = Cups::PrintJob.new("/non/existent/file", "bollocks_printer")
46
+
47
+ assert !Cups.show_destinations.include?(pj.instance_variable_get(:@printer))
48
+ end
49
+ end
50
+
51
+ def test_we_cant_print_nonexistent_files
52
+ pj = Cups::PrintJob.new("soft_class")
53
+
54
+ assert_raise(RuntimeError) do
55
+ pj.print
56
+ end
57
+
58
+ assert_nil pj.job_id
59
+ end
60
+
61
+ def test_we_can_pass_args_down_as_options
62
+ options = {:foo => 'bar'}
63
+ pj = Cups::PrintJob.new(sample, @printer, options)
64
+ assert_equal(options, pj.job_options)
65
+ end
66
+
67
+ def test_we_can_only_pass_strings_down_as_options
68
+ options = {:foo => 'bar'}
69
+ pj = Cups::PrintJob.new(sample, @printer, options)
70
+ assert_raise(TypeError) { pj.print }
71
+ end
72
+
73
+ def test_we_can_omit_options_and_will_set_to_empty
74
+ pj = Cups::PrintJob.new(sample, @printer)
75
+ assert_equal({}, pj.job_options)
76
+ end
77
+
78
+ def test_print_job_cancellation
79
+ pj = Cups::PrintJob.new(sample, @printer)
80
+ pj.print
81
+ assert_not_nil pj.job_id
82
+ assert_equal pj.cancel, true
83
+ assert pj.job_id.is_a?(Fixnum)
84
+ end
85
+
86
+ def test_all_jobs_raises_with_nonexistent_printers
87
+ assert_raise(RuntimeError) { Cups.all_jobs(nil) }
88
+ end
89
+
90
+ def test_all_jobs_returns_hash
91
+ assert Cups.all_jobs(Cups.default_printer).is_a?(Hash)
92
+ end
93
+
94
+ def test_all_jobs_hash_contains_info_hash
95
+ pj = Cups::PrintJob.new(sample, @printer)
96
+ pj.print
97
+ info = Cups.all_jobs(@printer)[pj.job_id]
98
+ assert info.is_a?(Hash)
99
+ assert info.keys.all?{|key| [:title, :format, :submitted_by, :state, :size].include?(key)}
100
+ end
101
+
102
+ def test_dest_list_returns_array
103
+ assert Cups.show_destinations.is_a?(Array)
104
+ end
105
+
106
+ def test_dest_options_returns_hash_if_real
107
+ assert Cups.options_for(@printer).is_a?(Hash)
108
+ end
109
+
110
+ def test_dest_options_raises_exception_if_not_real
111
+ assert_raise(RuntimeError, "The printer or destination doesn't exist!") { Cups.options_for("bollocks_printer") }
112
+ end
113
+
114
+ def test_job_failed_boolean
115
+ pj = Cups::PrintJob.new(sample, @printer)
116
+ pj.print
117
+ pj.cancel
118
+ assert !pj.failed?
119
+ end
120
+
121
+ def test_returns_failure_string_on_cancellation
122
+ pj = Cups::PrintJob.new(blank_sample, @printer)
123
+ pj.print
124
+
125
+ # assert pj.job_id == 0 # Failed jobs have an ID of zero
126
+ # assert pj.failed?
127
+
128
+ # assert pj.error_reason.is_a?(Symbol)
129
+ end
130
+
131
+ def test_job_state_string
132
+ pj = Cups::PrintJob.new(sample, @printer)
133
+ assert_nil pj.state # A job can't have a state if it hasn't been assigned a job_id yet
134
+ assert !pj.completed?
135
+
136
+ pj.print
137
+
138
+ pj.cancel
139
+ assert pj.state == :cancelled
140
+ assert !pj.completed?
141
+ end
142
+
143
+ def test_print_job_attributes
144
+ pj = Cups::PrintJob.new(sample)
145
+ [:printer, :filename, :job_id].each do |attr|
146
+ assert pj.respond_to?(attr)
147
+ end
148
+ end
149
+
150
+ private
151
+
152
+ def sample
153
+ "#{File.dirname(__FILE__)}/sample.txt"
154
+ end
155
+
156
+ def blank_sample
157
+ "#{File.dirname(__FILE__)}/sample_blank.txt"
158
+ end
159
+ 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,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thorsson_cups
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 8
9
+ version: 0.0.8
10
+ platform: ruby
11
+ authors:
12
+ - Ivan Turkovic
13
+ - Chris Mowforth
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-08 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ 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"
23
+ email:
24
+ - me@ivanturkovic.com
25
+ - chris@mowforth.com
26
+ executables: []
27
+
28
+ extensions:
29
+ - ext/extconf.rb
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - test/cups_test.rb
34
+ - test/sample_blank.txt
35
+ - test/sample.txt
36
+ - ext/cups.c
37
+ - ext/ruby_cups.h
38
+ - ext/extconf.rb
39
+ - lib/cups/printer/printer.rb
40
+ - lib/cups/print_job/transient.rb
41
+ has_rdoc: true
42
+ homepage: https://github.com/Thorsson/cups
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ requirements: []
67
+
68
+ rubyforge_project: thorsson_cups
69
+ rubygems_version: 1.3.7
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: A lightweight Ruby library for printing.
73
+ test_files: []
74
+