fusuma 2.0.0 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +27 -22
  3. data/fusuma.gemspec +2 -4
  4. data/lib/fusuma.rb +11 -4
  5. data/lib/fusuma/config.rb +1 -1
  6. data/lib/fusuma/config/searcher.rb +1 -2
  7. data/lib/fusuma/environment.rb +1 -1
  8. data/lib/fusuma/libinput_command.rb +11 -11
  9. data/lib/fusuma/plugin/buffers/timer_buffer.rb +1 -3
  10. data/lib/fusuma/plugin/executors/command_executor.rb +10 -10
  11. data/lib/fusuma/plugin/executors/executor.rb +1 -1
  12. data/lib/fusuma/plugin/inputs/libinput_command_input.rb +9 -2
  13. data/lib/fusuma/plugin/manager.rb +3 -3
  14. data/lib/fusuma/version.rb +1 -1
  15. data/spec/helpers/config_helper.rb +20 -0
  16. data/spec/lib/config/searcher_spec.rb +179 -0
  17. data/spec/lib/config_spec.rb +104 -0
  18. data/spec/lib/custom_process_spec.rb +28 -0
  19. data/spec/lib/device_spec.rb +96 -0
  20. data/spec/lib/dummy_config.yml +31 -0
  21. data/spec/lib/fusuma_spec.rb +103 -0
  22. data/spec/lib/libinput-list-devices_iberianpig-XPS-9360.txt +181 -0
  23. data/spec/lib/libinput-list-devices_magic_trackpad.txt +51 -0
  24. data/spec/lib/libinput-list-devices_razer_razer_blade.txt +252 -0
  25. data/spec/lib/libinput-list-devices_thejinx0r.txt +361 -0
  26. data/spec/lib/libinput-list-devices_unavailable.txt +36 -0
  27. data/spec/lib/libinput_command_spec.rb +164 -0
  28. data/spec/lib/plugin/base_spec.rb +74 -0
  29. data/spec/lib/plugin/buffers/buffer_spec.rb +80 -0
  30. data/spec/lib/plugin/buffers/dummy_buffer.rb +20 -0
  31. data/spec/lib/plugin/buffers/gesture_buffer_spec.rb +172 -0
  32. data/spec/lib/plugin/detectors/detector_spec.rb +43 -0
  33. data/spec/lib/plugin/detectors/dummy_detector.rb +24 -0
  34. data/spec/lib/plugin/detectors/pinch_detector_spec.rb +119 -0
  35. data/spec/lib/plugin/detectors/rotate_detector_spec.rb +125 -0
  36. data/spec/lib/plugin/detectors/swipe_detector_spec.rb +118 -0
  37. data/spec/lib/plugin/events/event_spec.rb +30 -0
  38. data/spec/lib/plugin/events/records/gesture_record_spec.rb +22 -0
  39. data/spec/lib/plugin/events/records/record_spec.rb +31 -0
  40. data/spec/lib/plugin/events/records/text_record_spec.rb +26 -0
  41. data/spec/lib/plugin/executors/command_executor_spec.rb +57 -0
  42. data/spec/lib/plugin/executors/executor_spec.rb +164 -0
  43. data/spec/lib/plugin/filters/filter_spec.rb +92 -0
  44. data/spec/lib/plugin/filters/libinput_filter_spec.rb +120 -0
  45. data/spec/lib/plugin/inputs/input_spec.rb +70 -0
  46. data/spec/lib/plugin/inputs/libinput_command_input_spec.rb +121 -0
  47. data/spec/lib/plugin/inputs/timer_input_spec.rb +40 -0
  48. data/spec/lib/plugin/manager_spec.rb +27 -0
  49. data/spec/lib/plugin/parsers/parser_spec.rb +45 -0
  50. data/spec/spec_helper.rb +20 -0
  51. metadata +76 -35
  52. data/.github/FUNDING.yml +0 -8
  53. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
  54. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -17
  55. data/.github/pull_request_template.md +0 -9
  56. data/.github/stale.yml +0 -18
  57. data/.gitignore +0 -17
  58. data/.reek.yml +0 -96
  59. data/.rspec +0 -2
  60. data/.rubocop.yml +0 -43
  61. data/.rubocop_todo.yml +0 -55
  62. data/.solargraph.yml +0 -16
  63. data/.travis.yml +0 -9
  64. data/CHANGELOG.md +0 -456
  65. data/CODE_OF_CONDUCT.md +0 -74
  66. data/CONTRIBUTING.md +0 -72
  67. data/Gemfile +0 -23
  68. data/Rakefile +0 -15
@@ -0,0 +1,36 @@
1
+ Device: AT Translated Set 2 keyboard
2
+ Kernel: /dev/input/event4
3
+ Group: 9
4
+ Seat: seat0, default
5
+ Capabilities: keyboard
6
+ Tap-to-click: n/a
7
+ Tap-and-drag: n/a
8
+ Tap drag lock: n/a
9
+ Left-handed: n/a
10
+ Nat.scrolling: n/a
11
+ Middle emulation: n/a
12
+ Calibration: n/a
13
+ Scroll methods: none
14
+ Click methods: none
15
+ Disable-w-typing: n/a
16
+ Accel profiles: n/a
17
+ Rotation: n/a
18
+
19
+ Device: Dell WMI hotkeys
20
+ Kernel: /dev/input/event9
21
+ Group: 10
22
+ Seat: seat0, default
23
+ Capabilities: keyboard
24
+ Tap-to-click: n/a
25
+ Tap-and-drag: n/a
26
+ Tap drag lock: n/a
27
+ Left-handed: n/a
28
+ Nat.scrolling: n/a
29
+ Middle emulation: n/a
30
+ Calibration: n/a
31
+ Scroll methods: none
32
+ Click methods: none
33
+ Disable-w-typing: n/a
34
+ Accel profiles: n/a
35
+ Rotation: n/a
36
+
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require './lib/fusuma/libinput_command'
5
+
6
+ module Fusuma
7
+ RSpec.describe LibinputCommand do
8
+ let(:libinput_command) do
9
+ described_class.new(libinput_options: libinput_options, commands: commands)
10
+ end
11
+ let(:libinput_options) { [] }
12
+ let(:commands) { {} }
13
+ describe '#version' do
14
+ subject { libinput_command.version }
15
+
16
+ context 'when libinput-list-device is available' do
17
+ before do
18
+ allow(libinput_command).to receive('which')
19
+ .with('libinput') { false }
20
+ allow(libinput_command).to receive('which')
21
+ .with('libinput-list-devices') { true }
22
+ allow_any_instance_of(Kernel).to receive(:`)
23
+ .with('libinput-list-devices --version') { "1.6.3\n" }
24
+ end
25
+
26
+ it { is_expected.to eq '1.6.3' }
27
+ it { expect(libinput_command.new_cli_option_available?).to be false }
28
+ end
29
+
30
+ context 'when libinput is available' do
31
+ before do
32
+ allow(libinput_command).to receive('which')
33
+ .with('libinput') { true }
34
+ allow(libinput_command).to receive('which')
35
+ .with('libinput-list-devices') { false }
36
+ allow_any_instance_of(Kernel).to receive(:`)
37
+ .with('libinput --version') { "1.8\n" }
38
+ end
39
+
40
+ it { is_expected.to eq '1.8' }
41
+ it { expect(libinput_command.new_cli_option_available?).to be true }
42
+ end
43
+
44
+ context 'when libinput command is not found' do
45
+ before do
46
+ allow(libinput_command).to receive('which')
47
+ .with('libinput') { false }
48
+ allow(libinput_command).to receive('which')
49
+ .with('libinput-list-devices') { false }
50
+ end
51
+
52
+ it 'shold print error and exit 1' do
53
+ expect(MultiLogger).to receive(:error)
54
+ expect { subject }.to raise_error(SystemExit)
55
+ end
56
+ end
57
+ end
58
+
59
+ describe '#new_cli_option_available?' do
60
+ subject { libinput_command.new_cli_option_available? }
61
+ context 'with NEW_CLI_OPTION_VERSION' do
62
+ before do
63
+ allow(libinput_command).to receive(:version)
64
+ .and_return(LibinputCommand::NEW_CLI_OPTION_VERSION)
65
+ end
66
+ it { is_expected.to eq true }
67
+ end
68
+ context 'without NEW_CLI_OPTION_VERSION' do
69
+ before do
70
+ allow(libinput_command).to receive(:version)
71
+ .and_return(LibinputCommand::NEW_CLI_OPTION_VERSION - 0.1)
72
+ end
73
+ it { is_expected.to eq false }
74
+ end
75
+ end
76
+
77
+ describe 'list_devices' do
78
+ subject { libinput_command.list_devices }
79
+ after { subject }
80
+
81
+ before do
82
+ dummy_io = StringIO.new('dummy')
83
+ io = StringIO.new('dummy output')
84
+ allow(Open3).to receive(:popen3).with(anything).and_return([dummy_io, io, dummy_io,
85
+ dummy_io, nil])
86
+ end
87
+
88
+ context 'with the alternative command' do
89
+ let(:commands) { { list_devices_command: 'dummy_list_devices' } }
90
+
91
+ it 'should call dummy events' do
92
+ expect(Open3).to receive(:popen3).with(/dummy_list_devices/)
93
+ end
94
+ end
95
+
96
+ context 'with new cli version' do
97
+ before do
98
+ allow(libinput_command).to receive(:new_cli_option_available?)
99
+ .and_return(true)
100
+ end
101
+
102
+ it 'call `libinput list-devices`' do
103
+ command = 'libinput list-devices'
104
+ expect(Open3).to receive(:popen3)
105
+ .with(command)
106
+ end
107
+ end
108
+ context 'with old cli version' do
109
+ before do
110
+ allow(libinput_command).to receive(:new_cli_option_available?)
111
+ .and_return(false)
112
+ end
113
+
114
+ it 'call `libinput-list-devices`' do
115
+ command = 'libinput-list-devices'
116
+ expect(Open3).to receive(:popen3)
117
+ .with(command)
118
+ end
119
+ end
120
+ end
121
+
122
+ describe 'debug_events' do
123
+ before do
124
+ @dummy_io = StringIO.new('dummy')
125
+ allow(Process).to receive(:detach).with(anything).and_return(nil)
126
+ end
127
+ subject { libinput_command.debug_events(@dummy_io) }
128
+
129
+ context 'with the alternative command' do
130
+ before do
131
+ allow(libinput_command).to receive(:debug_events_with_options).and_return 'dummy_debug_events'
132
+ end
133
+
134
+ it 'should call dummy events' do
135
+ expect(Process).to receive(:spawn).with('dummy_debug_events',
136
+ { out: @dummy_io, in: '/dev/null' }).once
137
+ subject
138
+ end
139
+ end
140
+ end
141
+
142
+ describe '#debug_events_with_options' do
143
+ subject { libinput_command.debug_events_with_options }
144
+
145
+ context 'with new cli version' do
146
+ before do
147
+ allow(libinput_command)
148
+ .to receive(:new_cli_option_available?)
149
+ .and_return(true)
150
+ end
151
+ it { is_expected.to eq 'stdbuf -oL -- libinput debug-events' }
152
+ end
153
+
154
+ context 'with old cli version' do
155
+ before do
156
+ allow(libinput_command)
157
+ .to receive(:new_cli_option_available?)
158
+ .and_return(false)
159
+ end
160
+ it { is_expected.to eq 'stdbuf -oL -- libinput-debug-events' }
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require './lib/fusuma/plugin/base'
5
+ require './lib/fusuma/plugin/manager'
6
+
7
+ module Fusuma
8
+ module Plugin
9
+ class DummyPlugin < Base
10
+ def config_param_types
11
+ {
12
+ dummy_string: String,
13
+ dummy_list: Array,
14
+ dummy_bool: [TrueClass, FalseClass]
15
+ }
16
+ end
17
+ end
18
+
19
+ class DummyChildPlugin < DummyPlugin
20
+ end
21
+
22
+ RSpec.describe DummyPlugin do
23
+ before do
24
+ @dummy_plugin = DummyPlugin.new
25
+ @dummy_child_plugin = DummyChildPlugin.new
26
+
27
+ ConfigHelper.load_config_yml = <<-CONFIG
28
+ plugin:
29
+ dummy_plugin:
30
+ dummy_string: dummy
31
+ dummy_list:
32
+ - 1
33
+ - 2
34
+ - 3
35
+ dummy_bool: true
36
+ CONFIG
37
+ end
38
+
39
+ after do
40
+ Config.custom_path = nil
41
+ end
42
+ describe '.inherited' do
43
+ it 'should add required class to subclass on Manager' do
44
+ expect(Manager.plugins[Base.name]).to include(DummyPlugin)
45
+ end
46
+ end
47
+
48
+ describe '.plugins' do
49
+ it 'should list plugins' do
50
+ expect(DummyPlugin.plugins).to eq([DummyChildPlugin])
51
+ end
52
+ end
53
+
54
+ describe '#config_param_types' do
55
+ it 'should define class for config params' do
56
+ expect(@dummy_plugin.config_param_types).to be_a Hash
57
+ end
58
+ end
59
+
60
+ describe '#config_params' do
61
+ it 'should fetch options from config' do
62
+ expect(@dummy_plugin.config_params).to be_a Hash
63
+ expect(@dummy_plugin.config_params(:dummy_string)).to be_a String
64
+ end
65
+ end
66
+
67
+ describe '#config_index' do
68
+ it 'should return index' do
69
+ expect(@dummy_plugin.config_index).to be_a Config::Index
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require './lib/fusuma/plugin/events/event'
6
+ require_relative './dummy_buffer'
7
+
8
+ module Fusuma
9
+ module Plugin
10
+ module Buffers
11
+ RSpec.describe DummyBuffer do
12
+ before do
13
+ @buffer = DummyBuffer.new
14
+ end
15
+
16
+ describe '#type' do
17
+ subject { @buffer.type }
18
+ it { is_expected.to eq 'dummy' }
19
+ end
20
+
21
+ describe '#buffer' do
22
+ it 'should buffer event' do
23
+ event = Events::Event.new(tag: 'dummy', record: 'dummy record')
24
+ expect(@buffer.buffer(event)).to eq [event]
25
+ expect(@buffer.events).to eq [event]
26
+ end
27
+
28
+ it 'should NOT buffer event' do
29
+ event = Events::Event.new(tag: 'SHOULD NOT BUFFER', record: 'dummy record')
30
+ @buffer.buffer(event)
31
+ expect(@buffer.events).to eq []
32
+ end
33
+ end
34
+
35
+ describe '#source' do
36
+ subject { @buffer.source }
37
+
38
+ it { is_expected.to eq DummyBuffer::DEFAULT_SOURCE }
39
+
40
+ context 'with config' do
41
+ around do |example|
42
+ @source = 'custom_event'
43
+
44
+ ConfigHelper.load_config_yml = <<~CONFIG
45
+ plugin:
46
+ buffers:
47
+ dummy_buffer:
48
+ source: #{@source}
49
+ CONFIG
50
+
51
+ example.run
52
+
53
+ Config.custom_path = nil
54
+ end
55
+
56
+ it { is_expected.to eq @source }
57
+ end
58
+ end
59
+
60
+ describe '#config_params' do
61
+ around do |example|
62
+ ConfigHelper.load_config_yml = <<~CONFIG
63
+ plugin:
64
+ buffers:
65
+ dummy_buffer:
66
+ dummy: dummy
67
+ CONFIG
68
+
69
+ example.run
70
+
71
+ Config.custom_path = nil
72
+ end
73
+
74
+ subject { @buffer.config_params }
75
+ it { is_expected.to eq(dummy: 'dummy') }
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require './lib/fusuma/plugin/buffers/buffer'
4
+
5
+ module Fusuma
6
+ module Plugin
7
+ module Buffers
8
+ class DummyBuffer < Buffer
9
+ DEFAULT_SOURCE = 'dummy'
10
+
11
+ def config_param_types
12
+ {
13
+ source: String,
14
+ dummy: String
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require './lib/fusuma/plugin/events/event'
6
+ require './lib/fusuma/plugin/events/records/gesture_record'
7
+ require './lib/fusuma/plugin/buffers/gesture_buffer'
8
+
9
+ module Fusuma
10
+ module Plugin
11
+ module Buffers
12
+ RSpec.describe GestureBuffer do
13
+ before do
14
+ @buffer = GestureBuffer.new
15
+ delta = Events::Records::GestureRecord::Delta.new(-1, 0, 0, 0, 0, 0)
16
+ @event_generator = lambda { |time = nil, status = 'updating'|
17
+ Events::Event.new(time: time,
18
+ tag: 'libinput_gesture_parser',
19
+ record: Events::Records::GestureRecord.new(
20
+ status: status,
21
+ gesture: 'SWIPE',
22
+ finger: 3,
23
+ delta: delta
24
+ ))
25
+ }
26
+ end
27
+
28
+ describe '#type' do
29
+ it { expect(@buffer.type).to eq 'gesture' }
30
+ end
31
+
32
+ describe '#buffer' do
33
+ it 'should buffer gesture event' do
34
+ event = @event_generator.call
35
+ @buffer.buffer(event)
36
+ expect(@buffer.events).to eq [event]
37
+ end
38
+
39
+ it 'should NOT buffer other event' do
40
+ event = Events::Event.new(tag: 'SHOULD NOT BUFFER', record: 'dummy record')
41
+ @buffer.buffer(event)
42
+ expect(@buffer.events).to eq []
43
+ end
44
+
45
+ it 'should buffer begin/end' do
46
+ begin_event = @event_generator.call(nil, 'begin')
47
+ @buffer.buffer(begin_event)
48
+ expect(@buffer.events).to eq [begin_event]
49
+ end_event = @event_generator.call(nil, 'end')
50
+ @buffer.buffer(end_event)
51
+ expect(@buffer.events).to eq [begin_event, end_event]
52
+ end
53
+ end
54
+
55
+ describe '#clear_expired' do
56
+ it 'should keep only events generated within 30 seconds' do
57
+ time = Time.now
58
+ event1 = @event_generator.call(time)
59
+ @buffer.buffer(event1)
60
+ event2 = @event_generator.call(time + 100)
61
+ event3 = @event_generator.call(time + 100)
62
+ @buffer.buffer(event2)
63
+ @buffer.buffer(event3)
64
+
65
+ @buffer.clear_expired(current_time: time + 100.1)
66
+
67
+ expect(@buffer.events).to eq [event2, event3]
68
+ end
69
+
70
+ context 'change seconds to keep' do
71
+ around do |example|
72
+ ConfigHelper.load_config_yml = <<~CONFIG
73
+ plugin:
74
+ buffers:
75
+ gesture_buffer:
76
+ seconds_to_keep: 0.3
77
+ CONFIG
78
+
79
+ example.run
80
+
81
+ Config.custom_path = nil
82
+ end
83
+
84
+ it 'should keep only events generated within 0.3 seconds' do
85
+ expect(@buffer.config_params).to eq(seconds_to_keep: 0.3)
86
+ time = Time.now
87
+ event1 = @event_generator.call(time)
88
+ @buffer.buffer(event1)
89
+ event2 = @event_generator.call(time + 0.1)
90
+ @buffer.buffer(event2)
91
+ event3 = @event_generator.call(time + 0.2)
92
+ @buffer.buffer(event3)
93
+ @buffer.clear_expired(current_time: time + 0.29)
94
+ expect(@buffer.events).to eq [event1, event2, event3]
95
+
96
+ @buffer.clear_expired(current_time: time + 0.3)
97
+ expect(@buffer.events).to eq [event2, event3]
98
+ end
99
+ end
100
+ end
101
+
102
+ describe '#source' do
103
+ it { expect(@buffer.source).to eq GestureBuffer::DEFAULT_SOURCE }
104
+
105
+ context 'with config' do
106
+ around do |example|
107
+ @source = 'custom_event'
108
+
109
+ ConfigHelper.load_config_yml = <<~CONFIG
110
+ plugin:
111
+ buffers:
112
+ gesture_buffer:
113
+ source: #{@source}
114
+ CONFIG
115
+
116
+ example.run
117
+
118
+ Config.custom_path = nil
119
+ end
120
+
121
+ it { expect(@buffer.source).to eq @source }
122
+ end
123
+ end
124
+
125
+ describe '#sum_attrs' do
126
+ it 'should calculate the sum of each attribute'
127
+ end
128
+
129
+ describe '#avg_attrs' do
130
+ it 'should calculate the average of each attribute'
131
+ end
132
+
133
+ describe '#finger' do
134
+ it 'should return number of fingers in gestures'
135
+ end
136
+
137
+ describe '#gesture' do
138
+ it 'should return string of gesture type'
139
+ end
140
+
141
+ describe '#empty?' do
142
+ context 'no gestures in buffer' do
143
+ before { @buffer.clear }
144
+ it { expect(@buffer.empty?).to be true }
145
+ end
146
+
147
+ context 'buffered some gestures' do
148
+ before { @buffer.buffer(@event_generator.call) }
149
+ it { expect(@buffer.empty?).to be false }
150
+ end
151
+ end
152
+
153
+ describe '#slect_by_events' do
154
+ context 'without block' do
155
+ it { expect(@buffer.select_by_events).to be_a Enumerator }
156
+ end
157
+
158
+ context 'with block' do
159
+ before do
160
+ @e1 = @event_generator.call(nil, 'hoge')
161
+ @e2 = @event_generator.call(nil, 'hoge')
162
+ @e3 = @event_generator.call(nil, 'fuga')
163
+ [@e1, @e2, @e3].each { |event| @buffer.buffer(event) }
164
+ end
165
+ it { expect(@buffer.select_by_events { |e| e.record.status == 'hoge' }).to be_a GestureBuffer }
166
+ it { expect(@buffer.select_by_events { |e| e.record.status == 'hoge' }.events).to eq [@e1, @e2] }
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end