ffi-gphoto2 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -1
- data/Rakefile +2 -0
- data/examples/intervalometer.rb +9 -7
- data/examples/list_config.rb +3 -5
- data/examples/live_view.rb +6 -12
- data/examples/record_movie.rb +10 -13
- data/ffi-gphoto2.gemspec +2 -1
- data/lib/ffi/gphoto2_port.rb +2 -2
- data/lib/gphoto2/camera/capture.rb +59 -0
- data/lib/gphoto2/camera/configuration.rb +136 -0
- data/lib/gphoto2/camera/event.rb +56 -0
- data/lib/gphoto2/camera/filesystem.rb +44 -0
- data/lib/gphoto2/camera.rb +95 -166
- data/lib/gphoto2/camera_abilities.rb +6 -6
- data/lib/gphoto2/camera_abilities_list.rb +7 -6
- data/lib/gphoto2/camera_event.rb +1 -8
- data/lib/gphoto2/camera_file.rb +15 -5
- data/lib/gphoto2/camera_file_path.rb +3 -5
- data/lib/gphoto2/camera_folder.rb +11 -0
- data/lib/gphoto2/camera_list.rb +3 -10
- data/lib/gphoto2/camera_widgets/camera_widget.rb +27 -14
- data/lib/gphoto2/camera_widgets/radio_camera_widget.rb +1 -0
- data/lib/gphoto2/camera_widgets/range_camera_widget.rb +1 -0
- data/lib/gphoto2/context.rb +2 -6
- data/lib/gphoto2/entry.rb +2 -0
- data/lib/gphoto2/port_info.rb +8 -6
- data/lib/gphoto2/port_info_list.rb +5 -6
- data/lib/gphoto2/port_result.rb +2 -0
- data/lib/gphoto2/struct.rb +11 -0
- data/lib/gphoto2/version.rb +1 -1
- data/lib/gphoto2.rb +13 -0
- data/spec/gphoto2/camera_abilities_list_spec.rb +5 -5
- data/spec/gphoto2/camera_abilities_spec.rb +7 -7
- data/spec/gphoto2/camera_file_path_spec.rb +2 -2
- data/spec/gphoto2/camera_file_spec.rb +7 -7
- data/spec/gphoto2/camera_folder_spec.rb +3 -3
- data/spec/gphoto2/camera_list_spec.rb +3 -3
- data/spec/gphoto2/camera_spec.rb +37 -272
- data/spec/gphoto2/camera_widgets/date_camera_widget_spec.rb +1 -1
- data/spec/gphoto2/camera_widgets/radio_camera_widget_spec.rb +4 -4
- data/spec/gphoto2/camera_widgets/range_camera_widget_spec.rb +2 -2
- data/spec/gphoto2/camera_widgets/text_camera_widget_spec.rb +1 -1
- data/spec/gphoto2/camera_widgets/toggle_camera_widget_spec.rb +2 -2
- data/spec/gphoto2/context_spec.rb +1 -1
- data/spec/gphoto2/entry_spec.rb +2 -2
- data/spec/gphoto2/port_info_list_spec.rb +4 -4
- data/spec/gphoto2/port_info_spec.rb +9 -10
- data/spec/spec_helper.rb +0 -7
- data/spec/support/shared_examples/camera/capture_examples.rb +41 -0
- data/spec/support/shared_examples/camera/configuration_examples.rb +161 -0
- data/spec/support/shared_examples/camera/event_examples.rb +39 -0
- data/spec/support/shared_examples/camera/filesystem_examples.rb +46 -0
- data/spec/support/shared_examples/camera_widget_examples.rb +13 -13
- metadata +32 -4
@@ -7,7 +7,7 @@ module GPhoto2
|
|
7
7
|
describe '#value' do
|
8
8
|
it 'has a Time return value' do
|
9
9
|
widget = DateCameraWidget.new(nil)
|
10
|
-
widget.
|
10
|
+
allow(widget).to receive(:value).and_return(Time.now)
|
11
11
|
expect(widget.value).to be_kind_of(Time)
|
12
12
|
end
|
13
13
|
end
|
@@ -7,7 +7,7 @@ module GPhoto2
|
|
7
7
|
describe '#value' do
|
8
8
|
it 'has a String return value' do
|
9
9
|
widget = RadioCameraWidget.new(nil)
|
10
|
-
widget.
|
10
|
+
allow(widget).to receive(:value).and_return('text')
|
11
11
|
expect(widget.value).to be_kind_of(String)
|
12
12
|
end
|
13
13
|
end
|
@@ -17,11 +17,11 @@ module GPhoto2
|
|
17
17
|
size = 2
|
18
18
|
|
19
19
|
widget = RadioCameraWidget.new(nil)
|
20
|
-
widget.
|
21
|
-
widget.
|
20
|
+
allow(widget).to receive(:count_choices).and_return(size)
|
21
|
+
allow(widget).to receive(:get_choice).and_return("choice")
|
22
22
|
|
23
23
|
expect(widget).to receive(:get_choice).exactly(size).times
|
24
|
-
|
24
|
+
|
25
25
|
choices = widget.choices
|
26
26
|
|
27
27
|
expect(choices.size).to eq(size)
|
@@ -7,7 +7,7 @@ module GPhoto2
|
|
7
7
|
describe '#value' do
|
8
8
|
it 'has a Float return value' do
|
9
9
|
widget = RangeCameraWidget.new(nil)
|
10
|
-
widget.
|
10
|
+
allow(widget).to receive(:value).and_return(0.0)
|
11
11
|
expect(widget.value).to be_kind_of(Float)
|
12
12
|
end
|
13
13
|
end
|
@@ -18,7 +18,7 @@ module GPhoto2
|
|
18
18
|
range = (min..max).step(inc).to_a
|
19
19
|
|
20
20
|
widget = RangeCameraWidget.new(nil)
|
21
|
-
widget.
|
21
|
+
allow(widget).to receive(:get_range).and_return([min, max, inc])
|
22
22
|
|
23
23
|
expect(widget.range).to eq(range)
|
24
24
|
end
|
@@ -7,7 +7,7 @@ module GPhoto2
|
|
7
7
|
describe '#value' do
|
8
8
|
it 'has a String return value' do
|
9
9
|
widget = TextCameraWidget.new(nil)
|
10
|
-
widget.
|
10
|
+
allow(widget).to receive(:value).and_return('text')
|
11
11
|
expect(widget.value).to be_kind_of(String)
|
12
12
|
end
|
13
13
|
end
|
@@ -7,13 +7,13 @@ module GPhoto2
|
|
7
7
|
describe '#value' do
|
8
8
|
it 'can have a TrueClass return value' do
|
9
9
|
widget = ToggleCameraWidget.new(nil)
|
10
|
-
widget.
|
10
|
+
allow(widget).to receive(:value).and_return(true)
|
11
11
|
expect(widget.value).to be_kind_of(TrueClass)
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'can have a FalseClass return value' do
|
15
15
|
widget = ToggleCameraWidget.new(nil)
|
16
|
-
widget.
|
16
|
+
allow(widget).to receive(:value).and_return(false)
|
17
17
|
expect(widget.value).to be_kind_of(FalseClass)
|
18
18
|
end
|
19
19
|
end
|
data/spec/gphoto2/entry_spec.rb
CHANGED
@@ -8,8 +8,8 @@ module GPhoto2
|
|
8
8
|
let(:value) { 'usb:250,006' }
|
9
9
|
|
10
10
|
before do
|
11
|
-
entry.
|
12
|
-
entry.
|
11
|
+
allow(entry).to receive(:get_name).and_return(name)
|
12
|
+
allow(entry).to receive(:get_value).and_return(value)
|
13
13
|
end
|
14
14
|
|
15
15
|
describe '#name' do
|
@@ -3,8 +3,8 @@ require 'spec_helper'
|
|
3
3
|
module GPhoto2
|
4
4
|
describe PortInfoList do
|
5
5
|
before do
|
6
|
-
PortInfoList.
|
7
|
-
PortInfoList.
|
6
|
+
allow_any_instance_of(PortInfoList).to receive(:new)
|
7
|
+
allow_any_instance_of(PortInfoList).to receive(:load)
|
8
8
|
end
|
9
9
|
|
10
10
|
describe '#lookup_path' do
|
@@ -13,7 +13,7 @@ module GPhoto2
|
|
13
13
|
index = 0
|
14
14
|
|
15
15
|
list = PortInfoList.new
|
16
|
-
list.
|
16
|
+
allow(list).to receive(:_lookup_path).and_return(index)
|
17
17
|
|
18
18
|
expect(list.lookup_path(port)).to eq(index)
|
19
19
|
end
|
@@ -21,7 +21,7 @@ module GPhoto2
|
|
21
21
|
|
22
22
|
describe '#at' do
|
23
23
|
it 'returns a new PortInfo instance at the specified index' do
|
24
|
-
PortInfo.
|
24
|
+
allow_any_instance_of(PortInfo).to receive(:new)
|
25
25
|
|
26
26
|
list = PortInfoList.new
|
27
27
|
port_info = list.at(0)
|
@@ -6,17 +6,16 @@ module GPhoto2
|
|
6
6
|
let(:index) { 0 }
|
7
7
|
|
8
8
|
before do
|
9
|
-
PortInfo.
|
9
|
+
allow_any_instance_of(PortInfo).to receive(:new)
|
10
10
|
end
|
11
11
|
|
12
12
|
describe '.find' do
|
13
13
|
it 'returns a new PortInfo instance from a port path' do
|
14
|
-
PortInfoList.
|
15
|
-
PortInfoList.
|
16
|
-
PortInfoList.
|
17
|
-
|
18
|
-
|
19
|
-
end
|
14
|
+
allow_any_instance_of(PortInfoList).to receive(:new)
|
15
|
+
allow_any_instance_of(PortInfoList).to receive(:load)
|
16
|
+
allow_any_instance_of(PortInfoList).to receive(:lookup_path)
|
17
|
+
info = PortInfo.new(port_info_list, index)
|
18
|
+
allow_any_instance_of(PortInfoList).to receive(:[]).and_return(info)
|
20
19
|
|
21
20
|
port_info = PortInfo.find('usb:250,006')
|
22
21
|
expect(port_info).to be_kind_of(PortInfo)
|
@@ -27,7 +26,7 @@ module GPhoto2
|
|
27
26
|
it 'returns the name of the port' do
|
28
27
|
name = 'name'
|
29
28
|
port_info = PortInfo.new(port_info_list, index)
|
30
|
-
port_info.
|
29
|
+
allow(port_info).to receive(:get_name).and_return(name)
|
31
30
|
expect(port_info.name).to eq(name)
|
32
31
|
end
|
33
32
|
end
|
@@ -36,7 +35,7 @@ module GPhoto2
|
|
36
35
|
it 'returns the path of the port' do
|
37
36
|
path = 'path'
|
38
37
|
port_info = PortInfo.new(port_info_list, index)
|
39
|
-
port_info.
|
38
|
+
allow(port_info).to receive(:get_path).and_return(path)
|
40
39
|
expect(port_info.path).to eq(path)
|
41
40
|
end
|
42
41
|
end
|
@@ -45,7 +44,7 @@ module GPhoto2
|
|
45
44
|
it 'returns the type of the port' do
|
46
45
|
type = :usb
|
47
46
|
port_info = PortInfo.new(port_info_list, index)
|
48
|
-
port_info.
|
47
|
+
allow(port_info).to receive(:get_type).and_return(type)
|
49
48
|
expect(port_info.type).to eq(type)
|
50
49
|
end
|
51
50
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,10 +3,3 @@ require 'gphoto2'
|
|
3
3
|
|
4
4
|
__dir__ ||= File.dirname(__FILE__)
|
5
5
|
Dir[File.join(__dir__, 'support/**/*.rb')].each { |f| require f }
|
6
|
-
|
7
|
-
RSpec.configure do |config|
|
8
|
-
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
-
config.run_all_when_everything_filtered = true
|
10
|
-
config.filter_run :focus
|
11
|
-
config.order = 'random'
|
12
|
-
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module GPhoto2
|
2
|
+
shared_examples_for Camera::Capture do
|
3
|
+
describe '#capture' do
|
4
|
+
let(:camera) { Camera.new(model, port) }
|
5
|
+
let(:path) { double('camera_file_path', folder: 'folder', name: 'name') }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(camera).to receive(:_capture).and_return(path)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'saves the camera configuration' do
|
12
|
+
expect(camera).to receive(:save)
|
13
|
+
camera.capture
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns a new CameraFile' do
|
17
|
+
expect(camera).to receive(:_capture)
|
18
|
+
expect(camera.capture).to be_kind_of(CameraFile)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#preview' do
|
23
|
+
let(:camera) { Camera.new(model, port) }
|
24
|
+
let(:file) { double('camera_file') }
|
25
|
+
|
26
|
+
before do
|
27
|
+
allow(camera).to receive(:save)
|
28
|
+
allow(camera).to receive(:capture_preview).and_return(file)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'saves the camera configuration' do
|
32
|
+
expect(camera).to receive(:save)
|
33
|
+
camera.preview
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'returns a new CameraFile' do
|
37
|
+
expect(camera.preview).to eq(file)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module GPhoto2
|
2
|
+
shared_examples_for Camera::Configuration do
|
3
|
+
describe '#window' do
|
4
|
+
let(:camera) { Camera.new(model, port) }
|
5
|
+
let(:window) { double('camera_widget') }
|
6
|
+
|
7
|
+
it 'always returns the same CameraWidget instance' do
|
8
|
+
allow(camera).to receive(:get_config).and_return(window)
|
9
|
+
expect(camera.window).to eq(window)
|
10
|
+
expect(camera.window).to eq(window)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#config' do
|
15
|
+
it 'returns a map of configuration widgets' do
|
16
|
+
camera = Camera.new(model, port)
|
17
|
+
window = double('camera_widget')
|
18
|
+
allow(camera).to receive(:window).and_return(window)
|
19
|
+
allow(window).to receive(:flatten).and_return({ 'iso' => window })
|
20
|
+
|
21
|
+
expect(camera.config).to eq({ 'iso' => window })
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#reload' do
|
26
|
+
let(:camera) do
|
27
|
+
camera = Camera.new(model, port)
|
28
|
+
window = double('camera_widget')
|
29
|
+
allow(window).to receive(:flatten)
|
30
|
+
allow(camera).to receive(:get_config).and_return(window)
|
31
|
+
camera
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'reloads the configuration from the camera' do
|
35
|
+
expect(camera).to receive(:get_config).once
|
36
|
+
camera.reload
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'marks the camera as not dirty' do
|
40
|
+
camera.reload
|
41
|
+
expect(camera.dirty?).to be(false)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#[]' do
|
46
|
+
let(:window) { double('camera_widget') }
|
47
|
+
|
48
|
+
let(:camera) do
|
49
|
+
camera = Camera.new(model, port)
|
50
|
+
allow(camera).to receive(:config).and_return({ 'iso' => window })
|
51
|
+
camera
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when the specified key exists' do
|
55
|
+
it 'returns a CameraWidget' do
|
56
|
+
expect(camera['iso']).to eq(window)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when the specified key does not exist' do
|
61
|
+
it 'returns nil' do
|
62
|
+
expect(camera['shutterspeed2']).to be_nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#[]=' do
|
68
|
+
let(:window) do
|
69
|
+
window = double('camera_widget')
|
70
|
+
expect(window).to receive(:value=).with(400)
|
71
|
+
window
|
72
|
+
end
|
73
|
+
|
74
|
+
let(:camera) do
|
75
|
+
camera = Camera.new(model, port)
|
76
|
+
allow(camera).to receive(:[]).and_return(window)
|
77
|
+
camera
|
78
|
+
end
|
79
|
+
|
80
|
+
it "sets a widget's value" do
|
81
|
+
camera['iso'] = 400
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'marks the camera as dirty' do
|
85
|
+
camera['iso'] = 400
|
86
|
+
expect(camera).to be_dirty
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'returns the passed value' do
|
90
|
+
expect(camera['iso'] = 400).to eq(400)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#update' do
|
95
|
+
let(:camera) do
|
96
|
+
camera = Camera.new(model, port)
|
97
|
+
allow(camera).to receive(:[]=)
|
98
|
+
allow(camera).to receive(:save)
|
99
|
+
camera
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'sets one or more camera setting' do
|
103
|
+
expect(camera).to receive(:[]=).exactly(2).times
|
104
|
+
camera.update('iso' => 400, 'shutterspeed2' => '1/30')
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'immediately saves the settings to the camera' do
|
108
|
+
expect(camera).to receive(:save)
|
109
|
+
camera.update
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#save' do
|
114
|
+
let(:camera) do
|
115
|
+
camera = Camera.new(model, port)
|
116
|
+
allow(camera).to receive_message_chain(:[], :value=)
|
117
|
+
allow(camera).to receive(:set_config)
|
118
|
+
camera
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when the camera is marked as dirty' do
|
122
|
+
it 'returns true' do
|
123
|
+
camera['iso'] = 400
|
124
|
+
expect(camera.save).to be(true)
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'marks the camera as not dirty' do
|
128
|
+
camera['iso'] = 400
|
129
|
+
camera.save
|
130
|
+
expect(camera).not_to be_dirty
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'when the camera is not marked as dirty' do
|
135
|
+
it 'returns false' do
|
136
|
+
expect(camera.save).to be(false)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#dirty?' do
|
142
|
+
context 'when the configuration changed' do
|
143
|
+
it 'returns true' do
|
144
|
+
camera = Camera.new(model, port)
|
145
|
+
allow(camera).to receive_message_chain(:[], :value=)
|
146
|
+
|
147
|
+
camera['iso'] = 400
|
148
|
+
|
149
|
+
expect(camera).to be_dirty
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'when the configuration has not changed' do
|
154
|
+
it 'returns false' do
|
155
|
+
camera = Camera.new(model, port)
|
156
|
+
expect(camera).not_to be_dirty
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module GPhoto2
|
2
|
+
shared_examples_for Camera::Event do
|
3
|
+
describe '#wait' do
|
4
|
+
let(:camera) { Camera.new(model, port) }
|
5
|
+
let(:event) { double('camera_event') }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(camera).to receive(:wait_for_event).and_return(event)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'waits for a camera event' do
|
12
|
+
expect(camera).to receive(:wait_for_event)
|
13
|
+
camera.wait
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns an event symbol' do
|
17
|
+
expect(camera.wait).to eq(event)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#wait_for' do
|
22
|
+
let(:camera) { Camera.new(model, port) }
|
23
|
+
let(:event) { double('camera_event', type: :capture_complete) }
|
24
|
+
|
25
|
+
before do
|
26
|
+
allow(camera).to receive(:wait).and_return(event)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'blocks until a given event is returned from #wait' do
|
30
|
+
expect(camera).to receive(:wait)
|
31
|
+
camera.wait_for(:capture_complete)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'returns the first event of the given type' do
|
35
|
+
expect(camera.wait_for(:capture_complete)).to eq(event)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module GPhoto2
|
2
|
+
shared_examples_for Camera::Filesystem do
|
3
|
+
describe '#filesystem' do
|
4
|
+
let(:camera) { Camera.new(model, port) }
|
5
|
+
|
6
|
+
context 'when a path is passed' do
|
7
|
+
let(:path) { '/store_00010001' }
|
8
|
+
|
9
|
+
it 'assumes the path is absolute' do
|
10
|
+
fs = camera.filesystem(path[1..-1])
|
11
|
+
expect(fs.path).to eq(path)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns a folder at the path that was passed' do
|
15
|
+
fs = camera.filesystem(path)
|
16
|
+
expect(fs.path).to eq(path)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when no path is passed' do
|
21
|
+
it 'returns a folder at the root of the filesystem' do
|
22
|
+
fs = camera.filesystem
|
23
|
+
expect(fs.path).to eq('/')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#file' do
|
29
|
+
it 'retrieves a file from the camera' do
|
30
|
+
camera = Camera.new(model, port)
|
31
|
+
allow(camera).to receive(:file_get)
|
32
|
+
expect(camera).to receive(:file_get)
|
33
|
+
camera.file(double('camera_file'))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#delete' do
|
38
|
+
it 'deletes a file from the camera' do
|
39
|
+
camera = Camera.new(model, port)
|
40
|
+
allow(camera).to receive(:file_delete)
|
41
|
+
expect(camera).to receive(:file_delete)
|
42
|
+
camera.delete(double('camera_file'))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|