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,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require './lib/fusuma/plugin/events/records/gesture_record'
5
+
6
+ module Fusuma
7
+ module Plugin
8
+ module Events
9
+ module Records
10
+ RSpec.describe GestureRecord do
11
+ let(:record) do
12
+ described_class.new(status: 'updating',
13
+ gesture: 'swipe',
14
+ finger: 3,
15
+ direction: direction)
16
+ end
17
+ let(:direction) { GestureRecord::Delta.new(0, 0, 1, 0) }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require './lib/fusuma/plugin/events/records/record'
5
+
6
+ module Fusuma
7
+ module Plugin
8
+ module Events
9
+ module Records
10
+ RSpec.describe Record do
11
+ class DummyRecord < Records::Record
12
+ def type
13
+ :dummy
14
+ end
15
+ end
16
+ let(:record) { described_class.new }
17
+
18
+ describe '#type' do
19
+ it { expect { record.type }.to raise_error(NotImplementedError) }
20
+
21
+ context 'override #type' do
22
+ let(:record) { DummyRecord.new }
23
+ it { expect { record.type }.not_to raise_error(NotImplementedError) }
24
+ it { expect(record.type).to eq :dummy }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require './lib/fusuma/plugin/events/records/text_record'
5
+
6
+ module Fusuma
7
+ module Plugin
8
+ module Events
9
+ module Records
10
+ RSpec.describe TextRecord do
11
+ let(:record) { described_class.new('this is dummy') }
12
+
13
+ describe '#type' do
14
+ subject { record.type }
15
+ it { is_expected.to eq :text }
16
+ end
17
+
18
+ describe '#to_s' do
19
+ subject { record.to_s }
20
+ it { is_expected.to eq 'this is dummy' }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require './lib/fusuma/plugin/executors/command_executor'
5
+ require './lib/fusuma/plugin/events/event'
6
+
7
+ module Fusuma
8
+ module Plugin
9
+ module Executors
10
+ RSpec.describe CommandExecutor do
11
+ before do
12
+ index = Config::Index.new([:dummy, 1, :direction])
13
+ record = Events::Records::IndexRecord.new(index: index)
14
+ @event = Events::Event.new(tag: 'dummy_detector', record: record)
15
+ @executor = CommandExecutor.new
16
+ end
17
+
18
+ around do |example|
19
+ ConfigHelper.load_config_yml = <<~CONFIG
20
+ dummy:
21
+ 1:
22
+ direction:
23
+ command: 'echo dummy'
24
+ interval: 1
25
+ CONFIG
26
+
27
+ example.run
28
+
29
+ Config.custom_path = nil
30
+ end
31
+
32
+ describe '#execute' do
33
+ it 'spawn' do
34
+ command = 'echo dummy'
35
+ env = {}
36
+ expect(Process).to receive(:spawn).with(env, command)
37
+ expect(Process).to receive(:detach).with(anything)
38
+ @executor.execute(@event)
39
+ end
40
+ end
41
+
42
+ describe '#executable?' do
43
+ context 'detector is matched with config file' do
44
+ it { expect(@executor.executable?(@event)).to be_truthy }
45
+ end
46
+
47
+ context 'detector is NOT matched with config file' do
48
+ before do
49
+ @event.tag = 'invalid'
50
+ end
51
+ it { expect(@executor.executable?(@event)).to be_falsey }
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require './lib/fusuma/config'
6
+ require './lib/fusuma/plugin/executors/executor'
7
+ require './lib/fusuma/plugin/detectors/detector'
8
+ require './lib/fusuma/plugin/events/event'
9
+
10
+ module Fusuma
11
+ module Plugin
12
+ module Executors
13
+ RSpec.describe Executor do
14
+ before { @executor = Executor.new }
15
+
16
+ describe '#execute_key' do
17
+ it { expect { @executor.execute_keys }.to raise_error(NotImplementedError) }
18
+ end
19
+
20
+ describe '#execute' do
21
+ it { expect { @executor.execute('dummy') }.to raise_error(NotImplementedError) }
22
+ end
23
+
24
+ describe '#executable?' do
25
+ it { expect { @executor.executable?('dummy') }.to raise_error(NotImplementedError) }
26
+ end
27
+ end
28
+
29
+ class DummyExecutor < Executor
30
+ def execute_keys
31
+ [:dummy]
32
+ end
33
+
34
+ def execute(event)
35
+ index = Config::Index.new([*event.record.index.keys, :dummy])
36
+ content = Config.search(index)
37
+
38
+ # stdout
39
+ puts content if executable?(event)
40
+ end
41
+
42
+ def executable?(event)
43
+ event.tag == 'dummy'
44
+ end
45
+ end
46
+
47
+ RSpec.describe DummyExecutor do
48
+ before do
49
+ index = Config::Index.new([:dummy_gesture,
50
+ Config::Index::Key.new(:dummy_direction, skippable: true)])
51
+ record = Events::Records::IndexRecord.new(index: index)
52
+ @event = Events::Event.new(tag: 'dummy', record: record)
53
+ @executor = DummyExecutor.new
54
+ end
55
+
56
+ around do |example|
57
+ ConfigHelper.load_config_yml = <<~CONFIG
58
+ dummy_gesture:
59
+ dummy_direction:
60
+ dummy: 'echo dummy'
61
+ interval: 0.3
62
+
63
+ plugin:
64
+ executors:
65
+ dummy_executor:
66
+ dummy: dummy
67
+ CONFIG
68
+
69
+ example.run
70
+
71
+ Config.custom_path = nil
72
+ end
73
+
74
+ describe '#execute' do
75
+ it { expect { @executor.execute(@event) }.to output("echo dummy\n").to_stdout }
76
+ context 'without executable' do
77
+ before do
78
+ allow(@executor).to receive(:executable?).and_return false
79
+ end
80
+ it { expect { @executor.execute(@event) }.not_to output("echo dummy\n").to_stdout }
81
+ end
82
+ end
83
+
84
+ describe '#executable?' do
85
+ it { expect(@executor.executable?(@event)).to be_truthy }
86
+ end
87
+
88
+ describe 'interval' do
89
+ it 'should return interval from Config' do
90
+ interval_time = 0.3 * DummyExecutor::BASE_ONESHOT_INTERVAL
91
+ expect(@executor.interval(@event)).to eq interval_time
92
+ end
93
+
94
+ context 'without skippable direction' do
95
+ around do |example|
96
+ ConfigHelper.load_config_yml = <<~CONFIG
97
+ dummy_gesture:
98
+ interval: 0.1
99
+ dummy_direction:
100
+ dummy: 'echo dummy'
101
+
102
+ plugin:
103
+ executors:
104
+ dummy_executor:
105
+ dummy: dummy
106
+ CONFIG
107
+
108
+ example.run
109
+
110
+ Config.custom_path = nil
111
+ end
112
+ it 'should not return parent interval' do
113
+ expect(@executor.interval(@event)).to eq DummyExecutor::BASE_ONESHOT_INTERVAL
114
+ expect(@executor.interval(@event)).not_to eq 0.1 * DummyExecutor::BASE_ONESHOT_INTERVAL
115
+ end
116
+
117
+ context 'with Config::Searcher.skip' do
118
+ it 'should return parent interval' do
119
+ Config::Searcher.skip do
120
+ expect(@executor.interval(@event)).to eq 0.1 * DummyExecutor::BASE_ONESHOT_INTERVAL
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ describe 'enough_interval?' do
128
+ it 'should return true at first time' do
129
+ expect(@executor.enough_interval?(@event)).to eq true
130
+ end
131
+
132
+ context 'after update_interval' do
133
+ before do
134
+ @executor.update_interval(@event)
135
+ end
136
+ it 'should return false' do
137
+ expect(@executor.enough_interval?(@event)).to eq false
138
+ end
139
+
140
+ context 'after wait interval time' do
141
+ before do
142
+ # dummy_gesture/dummy_direction/interval => 0.3
143
+ interval_time = 0.3 * DummyExecutor::BASE_ONESHOT_INTERVAL
144
+
145
+ @event2 = Events::Event.new(
146
+ time: @event.time + interval_time,
147
+ tag: 'dummy',
148
+ record: @event.record
149
+ )
150
+ end
151
+ it 'should return true after wait' do
152
+ expect(@executor.enough_interval?(@event2)).to eq true
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ describe '#config_params' do
159
+ it { expect(@executor.config_params).to eq(dummy: 'dummy') }
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'tempfile'
5
+
6
+ require './lib/fusuma/config'
7
+ require './lib/fusuma/plugin/filters/filter'
8
+ require './lib/fusuma/plugin/events/event'
9
+
10
+ module Fusuma
11
+ module Plugin
12
+ module Filters
13
+ class DummyFilter < Filter
14
+ DEFAULT_SOURCE = 'dummy_input'
15
+
16
+ def config_param_types
17
+ {
18
+ source: String
19
+ }
20
+ end
21
+ end
22
+
23
+ RSpec.describe DummyFilter do
24
+ let(:filter) { DummyFilter.new }
25
+
26
+ describe '#source' do
27
+ subject { filter.source }
28
+
29
+ it { is_expected.to eq DummyFilter::DEFAULT_SOURCE }
30
+
31
+ context 'with config' do
32
+ around do |example|
33
+ @custom_source = 'custom_input'
34
+
35
+ ConfigHelper.load_config_yml = <<~CONFIG
36
+ plugin:
37
+ filters:
38
+ dummy_filter:
39
+ source: #{@custom_source}
40
+ CONFIG
41
+
42
+ example.run
43
+
44
+ Config.custom_path = nil
45
+ end
46
+
47
+ it { is_expected.to eq @custom_source }
48
+ end
49
+ end
50
+
51
+ describe '#filter' do
52
+ subject { filter.filter(event) }
53
+ let(:event) { Events::Event.new(tag: 'dummy_input', record: 'dummy') }
54
+
55
+ context 'when filter#keep? return false' do
56
+ before do
57
+ allow(filter).to receive(:keep?).and_return(false)
58
+ end
59
+
60
+ it { is_expected.to be nil }
61
+ end
62
+
63
+ context 'when filter#keep? return true' do
64
+ before do
65
+ allow(filter).to receive(:keep?).and_return(true)
66
+ end
67
+
68
+ it { is_expected.to be event }
69
+ end
70
+ end
71
+
72
+ describe '#config_params' do
73
+ around do |example|
74
+ ConfigHelper.load_config_yml = <<~CONFIG
75
+ plugin:
76
+ filters:
77
+ dummy_filter:
78
+ dummy: dummy
79
+ CONFIG
80
+
81
+ example.run
82
+
83
+ Config.custom_path = nil
84
+ end
85
+
86
+ subject { filter.config_params }
87
+ it { is_expected.to eq(dummy: 'dummy') }
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'tempfile'
5
+
6
+ require './lib/fusuma/config'
7
+ require './lib/fusuma/plugin/filters/libinput_device_filter'
8
+ require './lib/fusuma/plugin/events/event'
9
+
10
+ module Fusuma
11
+ module Plugin
12
+ module Filters
13
+ RSpec.describe LibinputDeviceFilter do
14
+ before do
15
+ @filter = LibinputDeviceFilter.new
16
+ end
17
+
18
+ describe '#source' do
19
+ it { expect(@filter.source).to eq LibinputDeviceFilter::DEFAULT_SOURCE }
20
+
21
+ context 'with config' do
22
+ around do |example|
23
+ @custom_source = 'custom_input'
24
+
25
+ ConfigHelper.load_config_yml = <<~CONFIG
26
+ plugin:
27
+ filters:
28
+ libinput_device_filter:
29
+ source: #{@custom_source}
30
+ CONFIG
31
+
32
+ example.run
33
+
34
+ Config.custom_path = nil
35
+ end
36
+
37
+ it { expect(@filter.source).to eq @custom_source }
38
+ end
39
+ end
40
+
41
+ describe '#filter' do
42
+ before do
43
+ @event = Events::Event.new(tag: 'libinput_command_input', record: 'dummy')
44
+ end
45
+
46
+ context 'when filter#keep? return false' do
47
+ before do
48
+ allow(@filter).to receive(:keep?).and_return(false)
49
+ end
50
+
51
+ it { expect(@filter.filter(@event)).to be nil }
52
+ end
53
+
54
+ context 'when filter#keep? return true' do
55
+ before do
56
+ allow(@filter).to receive(:keep?).and_return(true)
57
+ end
58
+
59
+ it { expect(@filter.filter(@event)).to be @event }
60
+ end
61
+ end
62
+
63
+ describe '#keep?' do
64
+ before do
65
+ device = Device.new(id: 'event18', name: 'Awesome Touchpad', available: true)
66
+ allow(Device).to receive(:all).and_return([device])
67
+ @keep_device = LibinputDeviceFilter::KeepDevice.new(name_patterns: [])
68
+ allow(@filter).to receive(:keep_device).and_return(@keep_device)
69
+ end
70
+
71
+ context 'when including record generated from touchpad' do
72
+ before do
73
+ text = ' event18 GESTURE_SWIPE_UPDATE +1.44s 4 11.23/ 1.00 (36.91/ 3.28 unaccelerated) '
74
+ @event = Events::Event.new(tag: 'libinput_command_input', record: text)
75
+ end
76
+ it 'should keep record' do
77
+ expect(@filter.keep?(@event.record)).to be true
78
+ end
79
+
80
+ context 'when including -' do
81
+ before do
82
+ text = '-event18 GESTURE_SWIPE_UPDATE +1.44s 4 11.23/ 1.00 (36.91/ 3.28 unaccelerated) '
83
+ @event = Events::Event.new(tag: 'libinput_command_input', record: text)
84
+ end
85
+ it 'should keep record' do
86
+ expect(@filter.keep?(@event.record)).to be true
87
+ end
88
+ end
89
+ end
90
+ context 'when new device is added' do
91
+ before do
92
+ text = '-event18 DEVICE_ADDED Apple Wireless Trackpad seat0 default group13 cap:pg size 132x112mm tap(dl off) left scroll-nat scroll-2fg-edge click-buttonareas-clickfing '
93
+ @event = Events::Event.new(tag: 'libinput_command_input', record: text)
94
+ end
95
+ it 'should reset KeepDevice' do
96
+ expect(@keep_device).to receive(:reset)
97
+ @filter.keep?(@event.record)
98
+ end
99
+
100
+ it 'discard DEVICE_ADDED record' do
101
+ expect(@filter.keep?(@event.record)).to be false
102
+ end
103
+
104
+ context 'when keep device is NOT matched' do
105
+ before do
106
+ @keep_device = LibinputDeviceFilter::KeepDevice.new(name_patterns: ['Microsoft Arc Mouse'])
107
+ allow(@filter).to receive(:keep_device).and_return(@keep_device)
108
+ end
109
+ it 'should NOT reset KeepDevice' do
110
+ expect(@keep_device).not_to receive(:reset)
111
+ # NOTE: @event.record is 'Apple Wireless Touchpad'
112
+ @filter.keep?(@event.record)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end