fusuma 2.0.0.pre → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +50 -11
  3. data/fusuma.gemspec +5 -6
  4. data/lib/fusuma.rb +87 -33
  5. data/lib/fusuma/config.rb +33 -40
  6. data/lib/fusuma/config/index.rb +34 -8
  7. data/lib/fusuma/config/searcher.rb +80 -4
  8. data/lib/fusuma/custom_process.rb +13 -0
  9. data/lib/fusuma/device.rb +19 -6
  10. data/lib/fusuma/environment.rb +4 -3
  11. data/lib/fusuma/hash_support.rb +40 -0
  12. data/lib/fusuma/libinput_command.rb +10 -15
  13. data/lib/fusuma/multi_logger.rb +2 -6
  14. data/lib/fusuma/plugin/base.rb +18 -15
  15. data/lib/fusuma/plugin/buffers/buffer.rb +3 -2
  16. data/lib/fusuma/plugin/buffers/gesture_buffer.rb +34 -25
  17. data/lib/fusuma/plugin/buffers/timer_buffer.rb +3 -3
  18. data/lib/fusuma/plugin/detectors/detector.rb +26 -5
  19. data/lib/fusuma/plugin/detectors/pinch_detector.rb +109 -58
  20. data/lib/fusuma/plugin/detectors/rotate_detector.rb +91 -50
  21. data/lib/fusuma/plugin/detectors/swipe_detector.rb +93 -56
  22. data/lib/fusuma/plugin/events/event.rb +5 -4
  23. data/lib/fusuma/plugin/events/records/context_record.rb +27 -0
  24. data/lib/fusuma/plugin/events/records/gesture_record.rb +9 -6
  25. data/lib/fusuma/plugin/events/records/index_record.rb +46 -14
  26. data/lib/fusuma/plugin/events/records/record.rb +1 -1
  27. data/lib/fusuma/plugin/events/records/text_record.rb +2 -1
  28. data/lib/fusuma/plugin/executors/command_executor.rb +21 -4
  29. data/lib/fusuma/plugin/executors/executor.rb +45 -3
  30. data/lib/fusuma/plugin/filters/filter.rb +1 -1
  31. data/lib/fusuma/plugin/filters/libinput_device_filter.rb +6 -7
  32. data/lib/fusuma/plugin/filters/libinput_timeout_filter.rb +2 -2
  33. data/lib/fusuma/plugin/inputs/input.rb +20 -7
  34. data/lib/fusuma/plugin/inputs/libinput_command_input.rb +17 -5
  35. data/lib/fusuma/plugin/inputs/timer_input.rb +7 -7
  36. data/lib/fusuma/plugin/manager.rb +22 -29
  37. data/lib/fusuma/plugin/parsers/libinput_gesture_parser.rb +10 -8
  38. data/lib/fusuma/plugin/parsers/parser.rb +8 -9
  39. data/lib/fusuma/string_support.rb +16 -0
  40. data/lib/fusuma/version.rb +1 -1
  41. data/spec/helpers/config_helper.rb +20 -0
  42. data/spec/lib/config/searcher_spec.rb +97 -0
  43. data/spec/lib/config_spec.rb +112 -0
  44. data/spec/lib/custom_process_spec.rb +28 -0
  45. data/spec/lib/device_spec.rb +96 -0
  46. data/spec/lib/dummy_config.yml +31 -0
  47. data/spec/lib/fusuma_spec.rb +103 -0
  48. data/spec/lib/libinput-list-devices_iberianpig-XPS-9360.txt +181 -0
  49. data/spec/lib/libinput-list-devices_magic_trackpad.txt +51 -0
  50. data/spec/lib/libinput-list-devices_razer_razer_blade.txt +252 -0
  51. data/spec/lib/libinput-list-devices_thejinx0r.txt +361 -0
  52. data/spec/lib/libinput-list-devices_unavailable.txt +36 -0
  53. data/spec/lib/libinput_command_spec.rb +160 -0
  54. data/spec/lib/plugin/base_spec.rb +74 -0
  55. data/spec/lib/plugin/buffers/buffer_spec.rb +80 -0
  56. data/spec/lib/plugin/buffers/dummy_buffer.rb +20 -0
  57. data/spec/lib/plugin/buffers/gesture_buffer_spec.rb +172 -0
  58. data/spec/lib/plugin/detectors/detector_spec.rb +43 -0
  59. data/spec/lib/plugin/detectors/dummy_detector.rb +24 -0
  60. data/spec/lib/plugin/detectors/pinch_detector_spec.rb +119 -0
  61. data/spec/lib/plugin/detectors/rotate_detector_spec.rb +125 -0
  62. data/spec/lib/plugin/detectors/swipe_detector_spec.rb +118 -0
  63. data/spec/lib/plugin/events/event_spec.rb +30 -0
  64. data/spec/lib/plugin/events/records/gesture_record_spec.rb +22 -0
  65. data/spec/lib/plugin/events/records/record_spec.rb +31 -0
  66. data/spec/lib/plugin/events/records/text_record_spec.rb +26 -0
  67. data/spec/lib/plugin/executors/command_executor_spec.rb +57 -0
  68. data/spec/lib/plugin/executors/executor_spec.rb +160 -0
  69. data/spec/lib/plugin/filters/filter_spec.rb +92 -0
  70. data/spec/lib/plugin/filters/libinput_filter_spec.rb +120 -0
  71. data/spec/lib/plugin/inputs/input_spec.rb +70 -0
  72. data/spec/lib/plugin/inputs/libinput_command_input_spec.rb +121 -0
  73. data/spec/lib/plugin/inputs/timer_input_spec.rb +40 -0
  74. data/spec/lib/plugin/manager_spec.rb +27 -0
  75. data/spec/lib/plugin/parsers/parser_spec.rb +45 -0
  76. data/spec/spec_helper.rb +20 -0
  77. metadata +84 -38
  78. data/.github/FUNDING.yml +0 -8
  79. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
  80. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -17
  81. data/.github/pull_request_template.md +0 -9
  82. data/.github/stale.yml +0 -18
  83. data/.gitignore +0 -17
  84. data/.reek.yml +0 -96
  85. data/.rspec +0 -2
  86. data/.rubocop.yml +0 -40
  87. data/.rubocop_todo.yml +0 -40
  88. data/.travis.yml +0 -11
  89. data/CHANGELOG.md +0 -456
  90. data/CODE_OF_CONDUCT.md +0 -74
  91. data/CONTRIBUTING.md +0 -72
  92. data/Gemfile +0 -18
  93. data/Rakefile +0 -15
@@ -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
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require './lib/fusuma/plugin/events/event'
6
+ require './lib/fusuma/plugin/detectors/detector'
7
+ require './lib/fusuma/config'
8
+ require_relative '../buffers/dummy_buffer'
9
+ require_relative './dummy_detector'
10
+
11
+ module Fusuma
12
+ module Plugin
13
+ module Detectors
14
+ RSpec.describe DummyDetector do
15
+ before do
16
+ @detector = DummyDetector.new
17
+ @buffer = Buffers::DummyBuffer.new
18
+ end
19
+
20
+ around do |example|
21
+ ConfigHelper.load_config_yml = <<~CONFIG
22
+ plugin:
23
+ detectors:
24
+ dummy_detector:
25
+ dummy: dummy
26
+ CONFIG
27
+
28
+ example.run
29
+
30
+ Config.custom_path = nil
31
+ end
32
+
33
+ describe '#detect' do
34
+ it { expect(@detector.detect([@buffer])).to be_a(Events::Event) }
35
+ end
36
+
37
+ describe '#config_params' do
38
+ it { expect(@detector.config_params).to eq(dummy: 'dummy') }
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require './lib/fusuma/plugin/detectors/detector'
4
+ require './lib/fusuma/plugin/buffers/buffer'
5
+ require './lib/fusuma/plugin/events/records/index_record'
6
+
7
+ module Fusuma
8
+ module Plugin
9
+ module Detectors
10
+ class DummyDetector < Detector
11
+ # @param buffers [Array<Buffers::Buffer>]
12
+ # @return [Event]
13
+ def detect(buffers)
14
+ buffers.each do |buffer|
15
+ next unless buffer.type == 'dummy'
16
+
17
+ record = Events::Records::IndexRecord.new(index: Config::Index.new(%w[dummy index]))
18
+ return create_event(record: record)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require './lib/fusuma/plugin/detectors/pinch_detector'
6
+ require './lib/fusuma/plugin/buffers/gesture_buffer'
7
+ require './lib/fusuma/plugin/events/event'
8
+ require './lib/fusuma/config'
9
+
10
+ module Fusuma
11
+ module Plugin
12
+ module Detectors
13
+ RSpec.describe PinchDetector do
14
+ before do
15
+ @detector = PinchDetector.new
16
+ @buffer = Buffers::GestureBuffer.new
17
+ end
18
+
19
+ around do |example|
20
+ ConfigHelper.load_config_yml = <<~CONFIG
21
+ threshold:
22
+ rotate: 1
23
+ CONFIG
24
+
25
+ example.run
26
+
27
+ Config.custom_path = nil
28
+ end
29
+
30
+ describe '#detect' do
31
+ context 'with no pinch event in buffer' do
32
+ before do
33
+ @buffer.clear
34
+ end
35
+ it { expect(@detector.detect([@buffer])).to eq nil }
36
+ end
37
+
38
+ context 'with not enough pinch events in buffer' do
39
+ before do
40
+ deltas = [
41
+ Events::Records::GestureRecord::Delta.new(0, 0, 0, 0, 1, 0),
42
+ Events::Records::GestureRecord::Delta.new(0, 0, 0, 0, 1.1, 0)
43
+ ]
44
+ events = create_events(deltas: deltas)
45
+
46
+ events.each { |event| @buffer.buffer(event) }
47
+ end
48
+ it 'should have repeat record' do
49
+ expect(@detector.detect([@buffer]).record.trigger).to eq :repeat
50
+ end
51
+ end
52
+
53
+ context 'with enough pinch IN event' do
54
+ before do
55
+ deltas = [
56
+ Events::Records::GestureRecord::Delta.new(0, 0, 0, 0, 1.0, 0),
57
+ Events::Records::GestureRecord::Delta.new(0, 0, 0, 0, 1.0, 0),
58
+ Events::Records::GestureRecord::Delta.new(0, 0, 0, 0, 2.0, 0)
59
+ ]
60
+ events = create_events(deltas: deltas)
61
+
62
+ events.each { |event| @buffer.buffer(event) }
63
+ end
64
+ it { expect(@detector.detect([@buffer])).to all be_a Events::Event }
65
+ it { expect(@detector.detect([@buffer]).map(&:record)).to all be_a Events::Records::IndexRecord }
66
+ it { expect(@detector.detect([@buffer]).map(&:record).map(&:index)).to all be_a Config::Index }
67
+
68
+ it 'should detect 3 fingers pinch-in (oneshot/repeat)' do
69
+ events = @detector.detect([@buffer])
70
+ expect(events[0].record.index.keys.map(&:symbol))
71
+ .to eq([:pinch, 3, :in])
72
+ expect(events[1].record.index.keys.map(&:symbol))
73
+ .to eq([:pinch, 3, :in, :update])
74
+ end
75
+ end
76
+
77
+ context 'with enough pinch OUT event' do
78
+ before do
79
+ deltas = [
80
+ Events::Records::GestureRecord::Delta.new(0, 0, 0, 0, 1.0, 0),
81
+ Events::Records::GestureRecord::Delta.new(0, 0, 0, 0, 0.6, 0),
82
+ Events::Records::GestureRecord::Delta.new(0, 0, 0, 0, 0.3, 0)
83
+ ]
84
+ events = create_events(deltas: deltas)
85
+
86
+ events.each { |event| @buffer.buffer(event) }
87
+ end
88
+ it 'should detect 3 fingers pinch-out (oneshot/repeat)' do
89
+ events = @detector.detect([@buffer])
90
+ expect(events[0].record.index.keys.map(&:symbol))
91
+ .to eq([:pinch, 3, :out])
92
+ expect(events[1].record.index.keys.map(&:symbol))
93
+ .to eq([:pinch, 3, :out, :update])
94
+ end
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ def create_events(deltas: [])
101
+ record_type = PinchDetector::GESTURE_RECORD_TYPE
102
+ deltas.map do |delta|
103
+ status = if deltas[0].equal? delta
104
+ 'begin'
105
+ else
106
+ 'update'
107
+ end
108
+
109
+ gesture_record = Events::Records::GestureRecord.new(status: status,
110
+ gesture: record_type,
111
+ finger: 3,
112
+ delta: delta)
113
+ Events::Event.new(tag: 'libinput_gesture_parser', record: gesture_record)
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end