cups 0.0.6 → 0.0.7

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/ext/cups.c CHANGED
@@ -1,44 +1,48 @@
1
1
  #include <ruby_cups.h>
2
2
 
3
- static int num_options;
4
- static cups_option_t *options;
5
3
  cups_dest_t *dests, *dest;
6
4
  VALUE rubyCups, printJobs;
7
5
 
8
6
  // Need to abstract this out of cups.c
9
- char* ipp_state_to_string(int state)
7
+ VALUE ipp_state_to_symbol(int state)
10
8
  {
11
9
 
12
- char *jstate;
10
+ VALUE jstate;
13
11
 
14
12
  switch (state) {
15
13
  case IPP_JOB_PENDING :
16
- jstate = "Pending...";
14
+ jstate = ID2SYM(rb_intern("pending"));
17
15
  break;
18
16
  case IPP_JOB_HELD :
19
- jstate = "Held";
17
+ jstate = ID2SYM(rb_intern("held"));
20
18
  break;
21
19
  case IPP_JOB_PROCESSING :
22
- jstate = "Processing...";
20
+ jstate = ID2SYM(rb_intern("processing"));
23
21
  break;
24
22
  case IPP_JOB_STOPPED :
25
- jstate = "Stopped";
23
+ jstate = ID2SYM(rb_intern("stopped"));
26
24
  break;
27
25
  case IPP_JOB_CANCELED :
28
- jstate = "Cancelled";
26
+ jstate = ID2SYM(rb_intern("cancelled"));
29
27
  break;
30
28
  case IPP_JOB_ABORTED :
31
- jstate = "Aborted";
29
+ jstate = ID2SYM(rb_intern("aborted"));
32
30
  break;
33
31
  case IPP_JOB_COMPLETED :
34
- jstate = "Completed";
32
+ jstate = ID2SYM(rb_intern("completed"));
35
33
  break;
36
34
  default:
37
- jstate = "Unknown Job Code...";
35
+ jstate = ID2SYM(rb_intern("unknown"));
38
36
  }
39
37
  return jstate;
40
38
  }
41
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
+ }
42
46
 
43
47
  /*
44
48
  * call-seq:
@@ -49,12 +53,18 @@ char* ipp_state_to_string(int state)
49
53
  */
50
54
  static VALUE job_init(int argc, VALUE* argv, VALUE self)
51
55
  {
52
- VALUE filename, printer;
56
+ VALUE filename, printer, job_options;
53
57
 
54
- rb_scan_args(argc, argv, "11", &filename, &printer);
58
+ rb_scan_args(argc, argv, "12", &filename, &printer, &job_options);
55
59
 
56
60
  rb_iv_set(self, "@filename", filename);
57
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
+
58
68
  if (NIL_P(printer)) {
59
69
 
60
70
  // Fall back to default printer
@@ -67,10 +77,7 @@ static VALUE job_init(int argc, VALUE* argv, VALUE self)
67
77
  }
68
78
 
69
79
  } else {
70
- // First call Cups#show_destinations
71
- VALUE dest_list = rb_funcall(rubyCups, rb_intern("show_destinations"), 0);
72
- // Then check the printer arg is included in the returned array...
73
- if (rb_ary_includes(dest_list, printer)) {
80
+ if (printer_exists(printer)) {
74
81
  rb_iv_set(self, "@printer", printer);
75
82
  } else {
76
83
  rb_raise(rb_eRuntimeError, "The printer or destination doesn't exist!");
@@ -79,32 +86,78 @@ static VALUE job_init(int argc, VALUE* argv, VALUE self)
79
86
  return self;
80
87
  }
81
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
+
82
102
  /*
83
103
  * call-seq:
84
104
  * print_job.print -> Fixnum
85
105
  *
86
106
  * Submit a print job to the selected printer or class. Returns true on success.
87
107
  */
88
- static VALUE cups_print(VALUE self, VALUE file, VALUE printer)
108
+ static VALUE cups_print(VALUE self)
89
109
  {
90
110
  int job_id;
91
- file = rb_iv_get(self, "@filename");
92
- printer = rb_iv_get(self, "@printer");
93
-
111
+ VALUE file = rb_iv_get(self, "@filename");
112
+ VALUE printer = rb_iv_get(self, "@printer");
113
+
94
114
  char *fname = RSTRING_PTR(file); // Filename
95
115
  char *target = RSTRING_PTR(printer); // Target printer string
96
-
116
+
97
117
  FILE *fp = fopen(fname,"r");
98
118
  // Check @filename actually exists...
99
119
  if( fp ) {
100
120
  fclose(fp);
101
- job_id = cupsPrintFile(target, fname, "rCUPS", num_options, options); // Do it.
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
+
102
154
  rb_iv_set(self, "@job_id", INT2NUM(job_id));
155
+
103
156
  return Qtrue;
104
157
  } else {
105
158
  // and if it doesn't...
106
159
  rb_raise(rb_eRuntimeError, "Couldn't find file");
107
- return self;
160
+ return Qfalse;
108
161
  }
109
162
  }
110
163
 
@@ -143,6 +196,7 @@ static VALUE cups_get_default(VALUE self)
143
196
  VALUE def_p = rb_str_new2(default_printer);
144
197
  return def_p;
145
198
  }
199
+ // should return nil if no default printer is found!
146
200
  }
147
201
 
148
202
  /*
@@ -254,7 +308,7 @@ static VALUE cups_get_job_state(VALUE self)
254
308
  // Free job array
255
309
  cupsFreeJobs(num_jobs, jobs);
256
310
 
257
- jstate = rb_str_new2(ipp_state_to_string(job_state));
311
+ jstate = ipp_state_to_symbol(job_state);
258
312
 
259
313
  return jstate;
260
314
  }
@@ -313,8 +367,15 @@ static VALUE cups_job_completed(VALUE self)
313
367
  *
314
368
  * [:title, :submitted_by, :size, :format, :state]
315
369
  */
370
+
371
+
316
372
  static VALUE cups_get_jobs(VALUE self, VALUE printer)
317
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
+
318
379
  VALUE job_list, job_info_hash, jid, jtitle, juser, jsize, jformat, jstate;
319
380
  int job_id;
320
381
  int num_jobs;
@@ -333,7 +394,7 @@ static VALUE cups_get_jobs(VALUE self, VALUE printer)
333
394
  juser = rb_str_new2(jobs[i].user);
334
395
  jsize = INT2NUM(jobs[i].size);
335
396
  jformat = rb_str_new2(jobs[i].format);
336
- jstate = rb_str_new2(ipp_state_to_string(jobs[i].state));
397
+ jstate = ipp_state_to_symbol(jobs[i].state);
337
398
 
338
399
  rb_hash_aset(job_info_hash, ID2SYM(rb_intern("title")), jtitle);
339
400
  rb_hash_aset(job_info_hash, ID2SYM(rb_intern("submitted_by")), juser);
@@ -359,6 +420,11 @@ static VALUE cups_get_jobs(VALUE self, VALUE printer)
359
420
  */
360
421
  static VALUE cups_get_options(VALUE self, VALUE printer)
361
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
+
362
428
  VALUE options_list;
363
429
  int i;
364
430
  char *printer_arg = RSTRING_PTR(printer);
@@ -394,6 +460,7 @@ void Init_cups() {
394
460
  rb_define_attr(printJobs, "printer", 1, 0);
395
461
  rb_define_attr(printJobs, "filename", 1, 0);
396
462
  rb_define_attr(printJobs, "job_id", 1, 0);
463
+ rb_define_attr(printJobs, "job_options", 1, 0);
397
464
 
398
465
  // Cups::PrintJob Methods
399
466
  rb_define_method(printJobs, "initialize", job_init, -1);
@@ -1,8 +1,12 @@
1
1
  #include <cups/cups.h>
2
+
3
+ // st.h is needed for ST_CONTINUE constant
2
4
  #ifdef __APPLE__
3
5
  #include <ruby/ruby.h>
6
+ #include <ruby/st.h>
4
7
  #else
5
8
  #include <ruby.h>
9
+ #include <st.h>
6
10
  #endif
7
11
 
8
12
  #ifndef MAXOPTS
@@ -1,6 +1,5 @@
1
1
  require "cups"
2
2
  require "tempfile"
3
- require "digest/sha1"
4
3
 
5
4
  module Cups
6
5
 
@@ -44,8 +43,7 @@ module Cups
44
43
  def initialize(data_string, printer=nil)
45
44
  raise "Temporary print job has no data!" if data_string.empty?
46
45
 
47
- sha1 = Digest::SHA1.hexdigest(Time.now.to_s)
48
- file = Tempfile.new(sha1)
46
+ file = Tempfile.new('')
49
47
  file.puts(data_string)
50
48
  file.close
51
49
 
@@ -55,4 +53,4 @@ module Cups
55
53
  end
56
54
 
57
55
  end
58
- end
56
+ end
@@ -1,3 +1,6 @@
1
+ $LOAD_PATH.unshift File.expand_path( File.dirname(__FILE__) )
2
+
3
+ require 'rubygems'
1
4
  require "cups"
2
5
  require "test/unit"
3
6
 
@@ -5,6 +8,12 @@ require "test/unit"
5
8
  # the CUPS command line utilities installed and in your $PATH
6
9
 
7
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
+
8
17
  def test_same_printers_returned
9
18
  lplist = `lpstat -a`.split("\n").map { |pr| pr.split(' ').first }
10
19
  cups_destinations = Cups.show_destinations
@@ -18,7 +27,7 @@ class CupsTest < Test::Unit::TestCase
18
27
  end
19
28
 
20
29
  assert_nothing_raised do
21
- Cups::PrintJob.new("/path", "PDF_Printer")
30
+ Cups::PrintJob.new("/path", @printer)
22
31
  Cups::PrintJob.new("/path")
23
32
  end
24
33
  end
@@ -38,7 +47,7 @@ class CupsTest < Test::Unit::TestCase
38
47
  assert !Cups.show_destinations.include?(pj.instance_variable_get(:@printer))
39
48
  end
40
49
  end
41
-
50
+
42
51
  def test_we_cant_print_nonexistent_files
43
52
  pj = Cups::PrintJob.new("soft_class")
44
53
 
@@ -49,22 +58,43 @@ class CupsTest < Test::Unit::TestCase
49
58
  assert_nil pj.job_id
50
59
  end
51
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
+
52
78
  def test_print_job_cancellation
53
- pj = Cups::PrintJob.new(sample, "soft_class")
79
+ pj = Cups::PrintJob.new(sample, @printer)
54
80
  pj.print
55
81
  assert_not_nil pj.job_id
56
82
  assert_equal pj.cancel, true
57
83
  assert pj.job_id.is_a?(Fixnum)
58
84
  end
59
85
 
86
+ def test_all_jobs_raises_with_nonexistent_printers
87
+ assert_raise(RuntimeError) { Cups.all_jobs(nil) }
88
+ end
89
+
60
90
  def test_all_jobs_returns_hash
61
91
  assert Cups.all_jobs(Cups.default_printer).is_a?(Hash)
62
92
  end
63
93
 
64
94
  def test_all_jobs_hash_contains_info_hash
65
- pj = Cups::PrintJob.new(sample, "PDF_Printer")
95
+ pj = Cups::PrintJob.new(sample, @printer)
66
96
  pj.print
67
- info = Cups.all_jobs("PDF_Printer")[pj.job_id]
97
+ info = Cups.all_jobs(@printer)[pj.job_id]
68
98
  assert info.is_a?(Hash)
69
99
  assert info.keys.all?{|key| [:title, :format, :submitted_by, :state, :size].include?(key)}
70
100
  end
@@ -74,39 +104,39 @@ class CupsTest < Test::Unit::TestCase
74
104
  end
75
105
 
76
106
  def test_dest_options_returns_hash_if_real
77
- assert Cups.options_for("PDF_Printer").is_a?(Hash)
107
+ assert Cups.options_for(@printer).is_a?(Hash)
78
108
  end
79
109
 
80
- def test_dest_options_returns_nil_if_not_real
81
- assert_nil Cups.options_for("bollocks_printer")
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") }
82
112
  end
83
113
 
84
114
  def test_job_failed_boolean
85
- pj = Cups::PrintJob.new(sample, "soft_class")
115
+ pj = Cups::PrintJob.new(sample, @printer)
86
116
  pj.print
87
117
  pj.cancel
88
118
  assert !pj.failed?
89
119
  end
90
120
 
91
121
  def test_returns_failure_string_on_cancellation
92
- pj = Cups::PrintJob.new(blank_sample, "PDF_Printer")
122
+ pj = Cups::PrintJob.new(blank_sample, @printer)
93
123
  pj.print
94
-
95
- assert pj.job_id == 0 # Failed jobs have an ID of zero
96
- assert pj.failed?
97
-
98
- assert pj.error_reason.is_a?(String)
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)
99
129
  end
100
-
130
+
101
131
  def test_job_state_string
102
- pj = Cups::PrintJob.new(sample, "soft_class")
132
+ pj = Cups::PrintJob.new(sample, @printer)
103
133
  assert_nil pj.state # A job can't have a state if it hasn't been assigned a job_id yet
104
134
  assert !pj.completed?
105
135
 
106
136
  pj.print
107
137
 
108
138
  pj.cancel
109
- assert pj.state == "Cancelled"
139
+ assert pj.state == :cancelled
110
140
  assert !pj.completed?
111
141
  end
112
142
 
@@ -120,10 +150,10 @@ class CupsTest < Test::Unit::TestCase
120
150
  private
121
151
 
122
152
  def sample
123
- "#{Dir.pwd}/sample.txt"
153
+ "#{File.dirname(__FILE__)}/sample.txt"
124
154
  end
125
155
 
126
156
  def blank_sample
127
- "#{Dir.pwd}/sample_blank.txt"
157
+ "#{File.dirname(__FILE__)}/sample_blank.txt"
128
158
  end
129
159
  end
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cups
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 7
9
+ version: 0.0.7
5
10
  platform: ruby
6
11
  authors:
7
12
  - Chris Mowforth
@@ -9,7 +14,7 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-01-13 00:00:00 +00:00
17
+ date: 2010-11-12 00:00:00 +00:00
13
18
  default_executable:
14
19
  dependencies: []
15
20
 
@@ -41,21 +46,25 @@ rdoc_options: []
41
46
  require_paths:
42
47
  - lib
43
48
  required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
51
  - - ">="
46
52
  - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
47
55
  version: "0"
48
- version:
49
56
  required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
50
58
  requirements:
51
59
  - - ">="
52
60
  - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
53
63
  version: "0"
54
- version:
55
64
  requirements: []
56
65
 
57
66
  rubyforge_project: cups
58
- rubygems_version: 1.3.5
67
+ rubygems_version: 1.3.7
59
68
  signing_key:
60
69
  specification_version: 3
61
70
  summary: A lightweight Ruby library for printing.