ffi-gphoto2 0.5.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +11 -0
  3. data/CHANGELOG.md +44 -0
  4. data/README.md +22 -12
  5. data/examples/autofocus.rb +21 -0
  6. data/examples/capture.rb +8 -0
  7. data/examples/continuous_burst.rb +27 -0
  8. data/examples/list_config.rb +1 -0
  9. data/examples/list_files.rb +52 -0
  10. data/ffi-gphoto2.gemspec +9 -8
  11. data/lib/ffi/gphoto2.rb +14 -4
  12. data/lib/ffi/gphoto2/camera_abilities_list.rb +1 -1
  13. data/lib/ffi/gphoto2/camera_file_info.rb +10 -0
  14. data/lib/ffi/gphoto2/camera_file_info_audio.rb +11 -0
  15. data/lib/ffi/gphoto2/camera_file_info_fields.rb +14 -0
  16. data/lib/ffi/gphoto2/camera_file_info_file.rb +15 -0
  17. data/lib/ffi/gphoto2/camera_file_info_preview.rb +13 -0
  18. data/lib/ffi/gphoto2/camera_file_permissions.rb +9 -0
  19. data/lib/ffi/gphoto2/camera_file_status.rb +7 -0
  20. data/lib/ffi/gphoto2/camera_list.rb +1 -1
  21. data/lib/ffi/gphoto2/camera_widget.rb +1 -1
  22. data/lib/ffi/gphoto2_port.rb +21 -1
  23. data/lib/ffi/gphoto2_port/gp_port.rb +17 -0
  24. data/lib/ffi/gphoto2_port/gp_port_info_list.rb +1 -1
  25. data/lib/ffi/gphoto2_port/gp_port_serial_parity.rb +6 -0
  26. data/lib/ffi/gphoto2_port/gp_port_settings.rb +11 -0
  27. data/lib/ffi/gphoto2_port/gp_port_settings_serial.rb +12 -0
  28. data/lib/ffi/gphoto2_port/gp_port_settings_usb.rb +15 -0
  29. data/lib/ffi/gphoto2_port/gp_port_settings_usb_disk_direct.rb +8 -0
  30. data/lib/ffi/gphoto2_port/gp_port_settings_usb_scsi.rb +8 -0
  31. data/lib/gphoto2.rb +24 -4
  32. data/lib/gphoto2/camera.rb +10 -2
  33. data/lib/gphoto2/camera/capture.rb +22 -0
  34. data/lib/gphoto2/camera/configuration.rb +2 -1
  35. data/lib/gphoto2/camera/event.rb +3 -6
  36. data/lib/gphoto2/camera_abilities.rb +9 -0
  37. data/lib/gphoto2/camera_abilities_list.rb +1 -1
  38. data/lib/gphoto2/camera_file.rb +26 -8
  39. data/lib/gphoto2/camera_file_info/camera_file_info.rb +52 -0
  40. data/lib/gphoto2/camera_file_info/file_camera_file_info.rb +30 -0
  41. data/lib/gphoto2/camera_list.rb +1 -1
  42. data/lib/gphoto2/camera_widgets/camera_widget.rb +3 -7
  43. data/lib/gphoto2/camera_widgets/radio_camera_widget.rb +0 -4
  44. data/lib/gphoto2/camera_widgets/text_camera_widget.rb +1 -3
  45. data/lib/gphoto2/entry.rb +0 -4
  46. data/lib/gphoto2/port.rb +61 -0
  47. data/lib/gphoto2/port_info.rb +0 -4
  48. data/lib/gphoto2/port_info_list.rb +1 -1
  49. data/lib/gphoto2/version.rb +1 -1
  50. data/spec/gphoto2/camera_abilities_spec.rb +23 -0
  51. data/spec/gphoto2/camera_file_info/file_camera_file_info_spec.rb +56 -0
  52. data/spec/gphoto2/camera_file_spec.rb +17 -0
  53. data/spec/gphoto2/camera_spec.rb +11 -5
  54. data/spec/gphoto2/port_spec.rb +22 -0
  55. data/spec/gphoto2_spec.rb +18 -0
  56. data/spec/support/shared_examples/camera/capture_examples.rb +13 -0
  57. data/spec/support/shared_examples/camera/configuration_examples.rb +26 -18
  58. data/spec/support/shared_examples/camera_file_info_examples.rb +42 -0
  59. metadata +54 -24
@@ -0,0 +1,30 @@
1
+ module GPhoto2
2
+ class FileCameraFileInfo < CameraFileInfo
3
+ # @return [Integer, nil]
4
+ def width
5
+ fetch(:width)
6
+ end
7
+
8
+ # @return [Integer, nil]
9
+ def height
10
+ fetch(:height)
11
+ end
12
+
13
+ # @return [Boolean, nil]
14
+ def readable?
15
+ permissions = fetch(:permissions)
16
+ (permissions & CameraFilePermissions[:read]) != 0 if permissions
17
+ end
18
+
19
+ # @return [Boolean, nil]
20
+ def deletable?
21
+ permissions = fetch(:permissions)
22
+ (permissions & CameraFilePermissions[:delete]) != 0 if permissions
23
+ end
24
+
25
+ # @return [Time, nil] the last modification time
26
+ def mtime
27
+ Time.at(ptr[:mtime]) if has_field?(:mtime)
28
+ end
29
+ end
30
+ end
@@ -21,7 +21,7 @@ module GPhoto2
21
21
  private
22
22
 
23
23
  def new
24
- ptr = FFI::MemoryPointer.new(FFI::GPhoto2::CameraList)
24
+ ptr = FFI::MemoryPointer.new(:pointer)
25
25
  rc = gp_list_new(ptr)
26
26
  GPhoto2.check!(rc)
27
27
  @ptr = FFI::GPhoto2::CameraList.new(ptr.read_pointer)
@@ -70,7 +70,7 @@ module GPhoto2
70
70
  map
71
71
  end
72
72
 
73
- # @param [String]
73
+ # @return [String]
74
74
  def to_s
75
75
  value.to_s
76
76
  end
@@ -93,9 +93,7 @@ module GPhoto2
93
93
  end
94
94
 
95
95
  def get_name
96
- str = FFI::MemoryPointer.new(:string)
97
96
  str_ptr = FFI::MemoryPointer.new(:pointer)
98
- str_ptr.write_pointer(str)
99
97
 
100
98
  rc = gp_widget_get_name(ptr, str_ptr)
101
99
  GPhoto2.check!(rc)
@@ -113,11 +111,9 @@ module GPhoto2
113
111
  end
114
112
 
115
113
  def get_label
116
- str = FFI::MemoryPointer.new(:string)
117
114
  str_ptr = FFI::MemoryPointer.new(:pointer)
118
- str_ptr.write_pointer(str)
119
115
 
120
- rc = gp_widget_get_type(ptr, str_ptr)
116
+ rc = gp_widget_get_label(ptr, str_ptr)
121
117
  GPhoto2.check!(rc)
122
118
 
123
119
  str_ptr = str_ptr.read_pointer
@@ -131,7 +127,7 @@ module GPhoto2
131
127
  end
132
128
 
133
129
  def get_child(index)
134
- widget_ptr = FFI::MemoryPointer.new(FFI::GPhoto2::CameraWidget)
130
+ widget_ptr = FFI::MemoryPointer.new(:pointer)
135
131
  rc = gp_widget_get_child(ptr, index, widget_ptr)
136
132
  GPhoto2.check!(rc)
137
133
  widget = FFI::GPhoto2::CameraWidget.new(widget_ptr.read_pointer)
@@ -8,9 +8,7 @@ module GPhoto2
8
8
  protected
9
9
 
10
10
  def get_value
11
- val = FFI::MemoryPointer.new(:string)
12
11
  val_ptr = FFI::MemoryPointer.new(:pointer)
13
- val_ptr.write_pointer(val)
14
12
 
15
13
  rc = gp_widget_get_value(ptr, val_ptr)
16
14
  GPhoto2.check!(rc)
@@ -34,9 +32,7 @@ module GPhoto2
34
32
  end
35
33
 
36
34
  def get_choice(i)
37
- val = FFI::MemoryPointer.new(:string)
38
35
  val_ptr = FFI::MemoryPointer.new(:pointer)
39
- val_ptr.write_pointer(val)
40
36
 
41
37
  rc = gp_widget_get_choice(ptr, i, val_ptr)
42
38
  GPhoto2.check!(rc)
@@ -3,9 +3,7 @@ module GPhoto2
3
3
  protected
4
4
 
5
5
  def get_value
6
- val = FFI::MemoryPointer.new(:string)
7
6
  val_ptr = FFI::MemoryPointer.new(:pointer)
8
- val_ptr.write_pointer(val)
9
7
 
10
8
  rc = gp_widget_get_value(ptr, val_ptr)
11
9
  GPhoto2.check!(rc)
@@ -15,7 +13,7 @@ module GPhoto2
15
13
  end
16
14
 
17
15
  def set_value(text)
18
- val = FFI::MemoryPointer.from_string(text)
16
+ val = FFI::MemoryPointer.from_string(text.to_s)
19
17
  rc = gp_widget_set_value(ptr, val)
20
18
  GPhoto2.check!(rc)
21
19
  end
@@ -20,9 +20,7 @@ module GPhoto2
20
20
  private
21
21
 
22
22
  def get_name
23
- name = FFI::MemoryPointer.new(:string)
24
23
  ptr = FFI::MemoryPointer.new(:pointer)
25
- ptr.write_pointer(name)
26
24
 
27
25
  rc = gp_list_get_name(@camera_list.ptr, @index, ptr)
28
26
  GPhoto2.check!(rc)
@@ -32,9 +30,7 @@ module GPhoto2
32
30
  end
33
31
 
34
32
  def get_value
35
- value = FFI::MemoryPointer.new(:string)
36
33
  ptr = FFI::MemoryPointer.new(:pointer)
37
- ptr.write_pointer(value)
38
34
 
39
35
  rc = gp_list_get_value(@camera_list.ptr, @index, ptr)
40
36
  GPhoto2.check!(rc)
@@ -0,0 +1,61 @@
1
+ module GPhoto2
2
+ class Port
3
+ include FFI::GPhoto2Port
4
+ include GPhoto2::Struct
5
+
6
+ def initialize
7
+ @ptr = new
8
+ end
9
+
10
+ # @param [PortInfo] info
11
+ # @return [PortInfo]
12
+ def info=(info)
13
+ set_info(info)
14
+ info
15
+ end
16
+
17
+ # @return [void]
18
+ def open
19
+ _open
20
+ end
21
+
22
+ # @return [void]
23
+ def close
24
+ _close
25
+ end
26
+
27
+ # @return [void]
28
+ def reset
29
+ _reset
30
+ end
31
+
32
+ private
33
+
34
+ def new
35
+ ptr = FFI::MemoryPointer.new(:pointer)
36
+ rc = gp_port_new(ptr)
37
+ GPhoto2.check!(rc)
38
+ FFI::GPhoto2Port::GPPort.new(ptr.read_pointer)
39
+ end
40
+
41
+ def _open
42
+ rc = gp_port_open(ptr)
43
+ GPhoto2.check!(rc)
44
+ end
45
+
46
+ def _close
47
+ rc = gp_port_close(ptr)
48
+ GPhoto2.check!(rc)
49
+ end
50
+
51
+ def _reset
52
+ rc = gp_port_reset(ptr)
53
+ GPhoto2.check!(rc)
54
+ end
55
+
56
+ def set_info(port_info)
57
+ rc = gp_port_set_info(ptr, port_info.ptr)
58
+ GPhoto2.check!(rc)
59
+ end
60
+ end
61
+ end
@@ -44,9 +44,7 @@ module GPhoto2
44
44
  end
45
45
 
46
46
  def get_name
47
- name = FFI::MemoryPointer.new(:string)
48
47
  name_ptr = FFI::MemoryPointer.new(:pointer)
49
- name_ptr.write_pointer(name)
50
48
 
51
49
  rc = gp_port_info_get_name(ptr, name_ptr)
52
50
  GPhoto2.check!(rc)
@@ -56,9 +54,7 @@ module GPhoto2
56
54
  end
57
55
 
58
56
  def get_path
59
- path = FFI::MemoryPointer.new(:string)
60
57
  path_ptr = FFI::MemoryPointer.new(:pointer)
61
- path_ptr.write_pointer(path)
62
58
 
63
59
  rc = gp_port_info_get_path(ptr, path_ptr)
64
60
  GPhoto2.check!(rc)
@@ -25,7 +25,7 @@ module GPhoto2
25
25
  private
26
26
 
27
27
  def new
28
- ptr = FFI::MemoryPointer.new(GPPortInfoList)
28
+ ptr = FFI::MemoryPointer.new(:pointer)
29
29
  rc = gp_port_info_list_new(ptr)
30
30
  GPhoto2.check!(rc)
31
31
  @ptr = GPPortInfoList.new(ptr.read_pointer)
@@ -1,3 +1,3 @@
1
1
  module GPhoto2
2
- VERSION = '0.5.1'
2
+ VERSION = '0.8.0'
3
3
  end
@@ -34,5 +34,28 @@ module GPhoto2
34
34
  expect(abilities[key]).to eq(value)
35
35
  end
36
36
  end
37
+
38
+ describe '#operations' do
39
+ context 'when no or one operation is supported' do
40
+ it 'returns a bit field of supported operations' do
41
+ abilities = CameraAbilities.new(camera_abilities_list, index)
42
+ allow(abilities).to receive(:[]).and_return(:none)
43
+ expect(abilities.operations).to eq(0)
44
+ end
45
+ end
46
+
47
+ context 'when multiple operations are supported' do
48
+ it 'returns a bit field of supported operations' do
49
+ abilities = CameraAbilities.new(camera_abilities_list, index)
50
+
51
+ capture_image = FFI::GPhoto2::CameraOperation[:capture_image]
52
+ config = FFI::GPhoto2::CameraOperation[:config]
53
+ operations = capture_image | config
54
+
55
+ allow(abilities).to receive(:[]).and_return(operations)
56
+ expect(abilities.operations).to eq(0x11)
57
+ end
58
+ end
59
+ end
37
60
  end
38
61
  end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ module GPhoto2
5
+ describe FileCameraFileInfo do
6
+ it_behaves_like CameraFileInfo
7
+
8
+ let(:camera_file_info_file) do
9
+ OpenStruct.new(
10
+ fields: 0xff,
11
+ status: :not_downloaded,
12
+ size: 7355608,
13
+ type: 'image/jpeg',
14
+ width: 4928,
15
+ height: 3264,
16
+ permissions: 0xff,
17
+ mtime: Time.at(1467863342)
18
+ )
19
+ end
20
+
21
+ describe '#width' do
22
+ it 'returns the width of the file' do
23
+ info = FileCameraFileInfo.new(camera_file_info_file)
24
+ expect(info.width).to eq(4928)
25
+ end
26
+ end
27
+
28
+ describe '#height' do
29
+ it 'returns the height of the file' do
30
+ info = FileCameraFileInfo.new(camera_file_info_file)
31
+ expect(info.height).to eq(3264)
32
+ end
33
+ end
34
+
35
+ describe '#readable?' do
36
+ it 'returns whether the file is readable' do
37
+ info = FileCameraFileInfo.new(camera_file_info_file)
38
+ expect(info.readable?).to be(true)
39
+ end
40
+ end
41
+
42
+ describe '#deletable?' do
43
+ it 'returns whether the file is deletable' do
44
+ info = FileCameraFileInfo.new(camera_file_info_file)
45
+ expect(info.deletable?).to be(true)
46
+ end
47
+ end
48
+
49
+ describe '#mtime' do
50
+ it 'returns the last modification time of the file' do
51
+ info = FileCameraFileInfo.new(camera_file_info_file)
52
+ expect(info.mtime).to eq(Time.at(1467863342))
53
+ end
54
+ end
55
+ end
56
+ end
@@ -75,5 +75,22 @@ module GPhoto2
75
75
  expect(file.size).to eq(data_and_size.last)
76
76
  end
77
77
  end
78
+
79
+ describe '#info' do
80
+ context 'the file is a preview' do
81
+ it 'returns nil' do
82
+ file = CameraFile.new(camera)
83
+ expect(file.info).to be(nil)
84
+ end
85
+ end
86
+
87
+ context 'the file is a file' do
88
+ it 'it returns an instance of FileCameraFileInfo' do
89
+ file = CameraFile.new(camera, folder, name)
90
+ allow(file).to receive(:get_info).and_return(FileCameraFileInfo.new(nil))
91
+ expect(file.info).to be_kind_of(FileCameraFileInfo)
92
+ end
93
+ end
94
+ end
78
95
  end
79
96
  end
@@ -126,18 +126,24 @@ module GPhoto2
126
126
  let(:operations) { FFI::GPhoto2::CameraOperation[:capture_image] }
127
127
 
128
128
  before do
129
- allow(camera).to receive_message_chain(:abilities, :[]).and_return(operations)
129
+ allow(camera).to receive_message_chain(:abilities, :operations).and_return(operations)
130
+ end
131
+
132
+ context 'when the camera has the ability to perform an operation' do
133
+ it 'returns true' do
134
+ expect(camera.can?(:capture_image)).to be(true)
135
+ end
130
136
  end
131
137
 
132
138
  context 'when the camera does not have the ability perform an operation' do
133
- it 'return false' do
139
+ it 'returns false' do
134
140
  expect(camera.can?(:capture_audio)).to be(false)
135
141
  end
136
142
  end
137
143
 
138
- context 'when the camera does have the ability to perform an operation' do
139
- it 'returns true' do
140
- expect(camera.can?(:capture_image)).to be(true)
144
+ context 'an invalid operation is given' do
145
+ it 'returns false' do
146
+ expect(camera.can?(:dance)).to be(false)
141
147
  end
142
148
  end
143
149
  end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ module GPhoto2
4
+ describe Port do
5
+ before do
6
+ allow_any_instance_of(Port).to receive(:new)
7
+ end
8
+
9
+ describe '#info=' do
10
+ let(:port) { Port.new }
11
+
12
+ before do
13
+ allow(port).to receive(:set_info)
14
+ end
15
+
16
+ it 'returns the input value' do
17
+ info = double(:port_info)
18
+ expect(port.info = info).to eq(info)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe GPhoto2 do
4
+ describe '.check!' do
5
+ context 'the return code is not GP_OK' do
6
+ it 'raises GPhoto2::Error with a message and error code' do
7
+ code = -1
8
+ message = "Unspecified error (#{code})"
9
+
10
+ expect { GPhoto2.check!(code) }.to raise_error do |e|
11
+ expect(e).to be_kind_of(GPhoto2::Error)
12
+ expect(e.message).to eq(message)
13
+ expect(e.code).to eq(code)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -19,6 +19,19 @@ module GPhoto2
19
19
  end
20
20
  end
21
21
 
22
+ describe '#trigger' do
23
+ let(:camera) { Camera.new(model, port) }
24
+
25
+ before do
26
+ allow(camera).to receive(:trigger_capture)
27
+ end
28
+
29
+ it 'saves the camera configuration' do
30
+ expect(camera).to receive(:save)
31
+ camera.trigger
32
+ end
33
+ end
34
+
22
35
  describe '#preview' do
23
36
  let(:camera) { Camera.new(model, port) }
24
37
  let(:file) { double('camera_file') }
@@ -65,29 +65,37 @@ module GPhoto2
65
65
  end
66
66
 
67
67
  describe '#[]=' do
68
- let(:window) do
69
- window = double('camera_widget')
70
- expect(window).to receive(:value=).with(400)
71
- window
72
- end
68
+ let(:camera) { Camera.new(model, port) }
73
69
 
74
- let(:camera) do
75
- camera = Camera.new(model, port)
76
- allow(camera).to receive(:[]).and_return(window)
77
- camera
78
- end
70
+ context 'when the specified key is valid' do
71
+ let(:window) { double('camera_widget', :value= => 400) }
79
72
 
80
- it "sets a widget's value" do
81
- camera['iso'] = 400
82
- end
73
+ before do
74
+ allow(camera).to receive(:[]).and_return(window)
75
+ end
76
+
77
+ it "sets a widget's value" do
78
+ camera['iso'] = 400
79
+ end
80
+
81
+ it 'marks the camera as dirty' do
82
+ camera['iso'] = 400
83
+ expect(camera).to be_dirty
84
+ end
83
85
 
84
- it 'marks the camera as dirty' do
85
- camera['iso'] = 400
86
- expect(camera).to be_dirty
86
+ it 'returns the passed value' do
87
+ expect(camera['iso'] = 400).to eq(400)
88
+ end
87
89
  end
88
90
 
89
- it 'returns the passed value' do
90
- expect(camera['iso'] = 400).to eq(400)
91
+ context 'when the specified key is invalid' do
92
+ before do
93
+ allow(camera).to receive(:[]).and_return(nil)
94
+ end
95
+
96
+ it 'raises an ArgumentError' do
97
+ expect { camera['flavor'] = 'strawberry' }.to raise_error(ArgumentError)
98
+ end
91
99
  end
92
100
  end
93
101