fusuma 2.0.0.pre2 → 2.0.4

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -6
  3. data/fusuma.gemspec +3 -5
  4. data/lib/fusuma/config/searcher.rb +2 -0
  5. data/lib/fusuma/device.rb +3 -3
  6. data/lib/fusuma/environment.rb +1 -0
  7. data/lib/fusuma/libinput_command.rb +12 -12
  8. data/lib/fusuma/plugin/executors/command_executor.rb +10 -10
  9. data/lib/fusuma/plugin/inputs/input.rb +1 -0
  10. data/lib/fusuma/plugin/inputs/libinput_command_input.rb +9 -2
  11. data/lib/fusuma/plugin/manager.rb +12 -1
  12. data/lib/fusuma/version.rb +1 -1
  13. data/spec/helpers/config_helper.rb +20 -0
  14. data/spec/lib/config/searcher_spec.rb +97 -0
  15. data/spec/lib/config_spec.rb +112 -0
  16. data/spec/lib/custom_process_spec.rb +28 -0
  17. data/spec/lib/device_spec.rb +96 -0
  18. data/spec/lib/dummy_config.yml +31 -0
  19. data/spec/lib/fusuma_spec.rb +103 -0
  20. data/spec/lib/libinput-list-devices_iberianpig-XPS-9360.txt +181 -0
  21. data/spec/lib/libinput-list-devices_magic_trackpad.txt +51 -0
  22. data/spec/lib/libinput-list-devices_razer_razer_blade.txt +252 -0
  23. data/spec/lib/libinput-list-devices_thejinx0r.txt +361 -0
  24. data/spec/lib/libinput-list-devices_unavailable.txt +36 -0
  25. data/spec/lib/libinput_command_spec.rb +164 -0
  26. data/spec/lib/plugin/base_spec.rb +74 -0
  27. data/spec/lib/plugin/buffers/buffer_spec.rb +80 -0
  28. data/spec/lib/plugin/buffers/dummy_buffer.rb +20 -0
  29. data/spec/lib/plugin/buffers/gesture_buffer_spec.rb +172 -0
  30. data/spec/lib/plugin/detectors/detector_spec.rb +43 -0
  31. data/spec/lib/plugin/detectors/dummy_detector.rb +24 -0
  32. data/spec/lib/plugin/detectors/pinch_detector_spec.rb +119 -0
  33. data/spec/lib/plugin/detectors/rotate_detector_spec.rb +125 -0
  34. data/spec/lib/plugin/detectors/swipe_detector_spec.rb +118 -0
  35. data/spec/lib/plugin/events/event_spec.rb +30 -0
  36. data/spec/lib/plugin/events/records/gesture_record_spec.rb +22 -0
  37. data/spec/lib/plugin/events/records/record_spec.rb +31 -0
  38. data/spec/lib/plugin/events/records/text_record_spec.rb +26 -0
  39. data/spec/lib/plugin/executors/command_executor_spec.rb +57 -0
  40. data/spec/lib/plugin/executors/executor_spec.rb +160 -0
  41. data/spec/lib/plugin/filters/filter_spec.rb +92 -0
  42. data/spec/lib/plugin/filters/libinput_filter_spec.rb +120 -0
  43. data/spec/lib/plugin/inputs/input_spec.rb +70 -0
  44. data/spec/lib/plugin/inputs/libinput_command_input_spec.rb +121 -0
  45. data/spec/lib/plugin/inputs/timer_input_spec.rb +40 -0
  46. data/spec/lib/plugin/manager_spec.rb +27 -0
  47. data/spec/lib/plugin/parsers/parser_spec.rb +45 -0
  48. data/spec/spec_helper.rb +20 -0
  49. metadata +83 -42
  50. data/.github/FUNDING.yml +0 -8
  51. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
  52. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -17
  53. data/.github/pull_request_template.md +0 -9
  54. data/.github/stale.yml +0 -18
  55. data/.gitignore +0 -17
  56. data/.reek.yml +0 -96
  57. data/.rspec +0 -2
  58. data/.rubocop.yml +0 -43
  59. data/.rubocop_todo.yml +0 -55
  60. data/.solargraph.yml +0 -16
  61. data/.travis.yml +0 -9
  62. data/CHANGELOG.md +0 -456
  63. data/CODE_OF_CONDUCT.md +0 -74
  64. data/CONTRIBUTING.md +0 -72
  65. data/Gemfile +0 -23
  66. 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