ffi-gphoto2 0.5.1 → 0.8.0

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.
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