fusuma 2.0.0.pre2 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
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,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,160 @@
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' do
17
+ it do
18
+ expect { @executor.execute('dummy') }.to raise_error(NotImplementedError)
19
+ end
20
+ end
21
+
22
+ describe '#executable?' do
23
+ it do
24
+ expect { @executor.executable?('dummy') }.to raise_error(NotImplementedError)
25
+ end
26
+ end
27
+ end
28
+
29
+ class DummyExecutor < Executor
30
+ def execute(event)
31
+ index = Config::Index.new([*event.record.index.keys, :dummy])
32
+ content = Config.search(index)
33
+
34
+ # stdout
35
+ puts content if executable?(event)
36
+ end
37
+
38
+ def executable?(event)
39
+ event.tag == 'dummy'
40
+ end
41
+ end
42
+
43
+ RSpec.describe DummyExecutor do
44
+ before do
45
+ index = Config::Index.new([:dummy_gesture,
46
+ Config::Index::Key.new(:dummy_direction, skippable: true)])
47
+ record = Events::Records::IndexRecord.new(index: index)
48
+ @event = Events::Event.new(tag: 'dummy', record: record)
49
+ @executor = DummyExecutor.new
50
+ end
51
+
52
+ around do |example|
53
+ ConfigHelper.load_config_yml = <<~CONFIG
54
+ dummy_gesture:
55
+ dummy_direction:
56
+ dummy: 'echo dummy'
57
+ interval: 0.3
58
+
59
+ plugin:
60
+ executors:
61
+ dummy_executor:
62
+ dummy: dummy
63
+ CONFIG
64
+
65
+ example.run
66
+
67
+ Config.custom_path = nil
68
+ end
69
+
70
+ describe '#execute' do
71
+ it { expect { @executor.execute(@event) }.to output("echo dummy\n").to_stdout }
72
+ context 'without executable' do
73
+ before do
74
+ allow(@executor).to receive(:executable?).and_return false
75
+ end
76
+ it { expect { @executor.execute(@event) }.not_to output("echo dummy\n").to_stdout }
77
+ end
78
+ end
79
+
80
+ describe '#executable?' do
81
+ it { expect(@executor.executable?(@event)).to be_truthy }
82
+ end
83
+
84
+ describe 'interval' do
85
+ it 'should return interval from Config' do
86
+ interval_time = 0.3 * DummyExecutor::BASE_ONESHOT_INTERVAL
87
+ expect(@executor.interval(@event)).to eq interval_time
88
+ end
89
+
90
+ context 'without skippable direction' do
91
+ around do |example|
92
+ ConfigHelper.load_config_yml = <<~CONFIG
93
+ dummy_gesture:
94
+ interval: 0.1
95
+ dummy_direction:
96
+ dummy: 'echo dummy'
97
+
98
+ plugin:
99
+ executors:
100
+ dummy_executor:
101
+ dummy: dummy
102
+ CONFIG
103
+
104
+ example.run
105
+
106
+ Config.custom_path = nil
107
+ end
108
+ it 'should not return parent interval' do
109
+ expect(@executor.interval(@event)).to eq DummyExecutor::BASE_ONESHOT_INTERVAL
110
+ expect(@executor.interval(@event)).not_to eq 0.1 * DummyExecutor::BASE_ONESHOT_INTERVAL
111
+ end
112
+
113
+ context 'with Config::Searcher.skip' do
114
+ it 'should return parent interval' do
115
+ Config::Searcher.skip do
116
+ expect(@executor.interval(@event)).to eq 0.1 * DummyExecutor::BASE_ONESHOT_INTERVAL
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ describe 'enough_interval?' do
124
+ it 'should return true at first time' do
125
+ expect(@executor.enough_interval?(@event)).to eq true
126
+ end
127
+
128
+ context 'after update_interval' do
129
+ before do
130
+ @executor.update_interval(@event)
131
+ end
132
+ it 'should return false' do
133
+ expect(@executor.enough_interval?(@event)).to eq false
134
+ end
135
+
136
+ context 'after wait interval time' do
137
+ before do
138
+ # dummy_gesture/dummy_direction/interval => 0.3
139
+ interval_time = 0.3 * DummyExecutor::BASE_ONESHOT_INTERVAL
140
+
141
+ @event2 = Events::Event.new(
142
+ time: @event.time + interval_time,
143
+ tag: 'dummy',
144
+ record: @event.record
145
+ )
146
+ end
147
+ it 'should return true after wait' do
148
+ expect(@executor.enough_interval?(@event2)).to eq true
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ describe '#config_params' do
155
+ it { expect(@executor.config_params).to eq(dummy: 'dummy') }
156
+ end
157
+ end
158
+ end
159
+ end
160
+ 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