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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f7ab066b275d3d5bdf59d18a948d297d0e164f71d0611e6f999c71d962a8f6d
4
- data.tar.gz: f92ff70084e6b98482236b67b2f2c68d7424f7cb8ff1e9ad6b61f4a7d4bea244
3
+ metadata.gz: 8f19305771a0704b1f7294b9b54653f09d7d4f6153ffbdd19a6c23a753870b09
4
+ data.tar.gz: 3b6c9addcda816e7379e69bb258bd11f091ea39fbae37fc8e0ef4c9ca4b7dff7
5
5
  SHA512:
6
- metadata.gz: 885b781c3ec389cc6e37a68eb0799044e8792587145875d7c3facb59dc3a003cd53c4beb9d2a539f534f4947b2a5cf4d43442a9d3a0dba929744881feac7607c
7
- data.tar.gz: a79c1f4390694af343cb98901f30916c32642ff5318181a8191c855997eff64aea3dc4a88f02b51a7bfb2565ac7037965bb2816b24141eab6bcd6a23f9ce04dc
6
+ metadata.gz: 422dc7e58b8db650754c4939ec1946456bfdfb0a8e4af33d79a20d88d84190f393952e05e1d086f711fb1ee2e6c415c4ddf6861dba8d94bf84df4f4e0585374f
7
+ data.tar.gz: 02e75550adfd4a6f3e3d43b4a6326377d5182131bdd9d9f3ff3ca0abcb89888e0bca9eea8551868cc87edb0a706fb9b51ee97cc517e093566c7448729359ded2
data/README.md CHANGED
@@ -330,12 +330,13 @@ Fusuma plugins are provided with the `fusuma-plugin-XXXXX` naming convention and
330
330
 
331
331
  ### Available plugins
332
332
 
333
- | Name | About |
334
- | ------------------------------------------------------------------------------ | --------------------------------------------- |
335
- | [fusuma-plugin-sendkey](https://github.com/iberianpig/fusuma-plugin-sendkey) | Emulates keyboard events |
336
- | [fusuma-plugin-wmctrl](https://github.com/iberianpig/fusuma-plugin-wmctrl) | Manages Window and Workspace |
337
- | [fusuma-plugin-keypress](https://github.com/iberianpig/fusuma-plugin-keypress) | Detects gestures while pressing multiple keys |
338
- | [fusuma-plugin-tap](https://github.com/iberianpig/fusuma-plugin-tap) | Detects Tap and Hold gestures |
333
+ | Name | Version | About |
334
+ | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------- |
335
+ | [fusuma-plugin-sendkey](https://github.com/iberianpig/fusuma-plugin-sendkey) | ![Gem Version](https://badge.fury.io/rb/fusuma-plugin-sendkey.svg) | Emulates keyboard events |
336
+ | [fusuma-plugin-wmctrl](https://github.com/iberianpig/fusuma-plugin-wmctrl) | ![Gem Version](https://badge.fury.io/rb/fusuma-plugin-wmctrl.svg) | Manages Window and Workspace |
337
+ | [fusuma-plugin-keypress](https://github.com/iberianpig/fusuma-plugin-keypress) | ![Gem Version](https://badge.fury.io/rb/fusuma-plugin-keypress.svg) | Detects gestures while pressing multiple keys |
338
+ | [fusuma-plugin-tap](https://github.com/iberianpig/fusuma-plugin-tap) | ![Gem Version](https://badge.fury.io/rb/fusuma-plugin-tap.svg) | Detects Tap and Hold gestures |
339
+ | [fusuma-plugin-appmatcher](https://github.com/iberianpig/fusuma-plugin-appmatcher) | ![Gem Version](https://badge.fury.io/rb/fusuma-plugin-appmatcher.svg) | Configure app-specific gestures |
339
340
 
340
341
  ## Tutorial Video
341
342
 
data/fusuma.gemspec CHANGED
@@ -10,14 +10,13 @@ Gem::Specification.new do |spec|
10
10
  spec.authors = ['iberianpig']
11
11
  spec.email = ['yhkyky@gmail.com']
12
12
 
13
- spec.summary = 'Multitouch gestures with libinput driver on X11, Linux'
13
+ spec.summary = 'Multitouch gestures with libinput driver, Linux'
14
14
  spec.description = 'Fusuma is multitouch gesture recognizer. This gem makes your touchpad on Linux able to recognize swipes or pinchs and assign command to them. Read installation on Github(https://github.com/iberianpig/fusuma#installation).'
15
15
  spec.homepage = 'https://github.com/iberianpig/fusuma'
16
16
  spec.license = 'MIT'
17
17
 
18
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
- f.match(%r{^(test|spec|features)/})
20
- end
18
+ spec.files = Dir['{bin,lib,exe}/**/*', 'LICENSE*', 'README*', '*.gemspec']
19
+ spec.test_files = Dir['{test,spec,features}/**/*']
21
20
  spec.bindir = 'exe'
22
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
22
  spec.require_paths = ['lib']
@@ -25,5 +24,4 @@ Gem::Specification.new do |spec|
25
24
 
26
25
  spec.required_ruby_version = '>= 2.5.1' # https://packages.ubuntu.com/search?keywords=ruby&searchon=names&exact=1&suite=all&section=main
27
26
  # support bionic (18.04LTS) 2.5.1
28
- spec.add_dependency 'posix-spawn'
29
27
  end
@@ -32,6 +32,8 @@ module Fusuma
32
32
  end
33
33
 
34
34
  def search_with_context(index, location:, context:)
35
+ return nil if location.nil?
36
+
35
37
  return search(index, location: location[0]) if context == {}
36
38
 
37
39
  new_location = location.find do |conf|
data/lib/fusuma/device.rb CHANGED
@@ -36,9 +36,9 @@ module Fusuma
36
36
  # sort devices by capabilities of gesture
37
37
  # @return [Array]
38
38
  def all
39
- @all ||= fetch_devices.sort_by do |d|
40
- d.capabilities.match(/gesture/).to_s
41
- end
39
+ @all ||= fetch_devices.partition do |d|
40
+ d.capabilities.match?(/gesture/)
41
+ end.flatten
42
42
  end
43
43
 
44
44
  # @raise [SystemExit]
@@ -20,6 +20,7 @@ module Fusuma
20
20
  libinput_command = Plugin::Inputs::LibinputCommandInput.new.command
21
21
  MultiLogger.info "Fusuma: #{VERSION}"
22
22
  MultiLogger.info "libinput: #{libinput_command.version}"
23
+ MultiLogger.info "ruby #{ RUBY_VERSION }p#{ RUBY_PATCHLEVEL }"
23
24
  MultiLogger.info "OS: #{`uname -rsv`}".strip
24
25
  MultiLogger.info "Distribution: #{`cat /etc/issue`}".strip
25
26
  MultiLogger.info "Desktop session: #{`echo $DESKTOP_SESSION $XDG_SESSION_TYPE`}".strip
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'posix/spawn'
3
+ require 'open3'
4
4
 
5
5
  module Fusuma
6
6
  # Execute libinput command
@@ -33,20 +33,20 @@ module Fusuma
33
33
  def list_devices(&block)
34
34
  cmd = list_devices_command
35
35
  MultiLogger.debug(list_devices: cmd)
36
- p, i, o, e = POSIX::Spawn.popen4(cmd)
36
+ i, o, e, _w = Open3.popen3(cmd)
37
+ MultiLogger.error(e.read) if o.eof?
37
38
  i.close
39
+ e.close
38
40
  o.each(&block)
39
- ensure
40
- [i, o, e].each { |io| io.close unless io.closed? }
41
- Process.waitpid(p)
42
41
  end
43
42
 
44
- # @return [Integer, IO] return a latest line libinput debug-events
45
- def debug_events
46
- @debug_events = begin
47
- p, i, o, _e = POSIX::Spawn.popen4(debug_events_with_options)
48
- i.close
49
- [p, o]
43
+ # @return [Integer] return a latest line libinput debug-events
44
+ def debug_events(writer)
45
+ @debug_events ||= begin
46
+ pid = Process.spawn(debug_events_with_options, out: writer,
47
+ in: '/dev/null')
48
+ Process.detach(pid)
49
+ pid
50
50
  end
51
51
  end
52
52
 
@@ -60,7 +60,7 @@ module Fusuma
60
60
  elsif which('libinput-list-devices')
61
61
  'libinput-list-devices --version'
62
62
  else
63
- MultiLogger.error 'install libinput-tools'
63
+ MultiLogger.error 'Please install libinput-tools'
64
64
  exit 1
65
65
  end
66
66
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'posix/spawn'
4
3
  require_relative './executor'
5
4
 
6
5
  module Fusuma
@@ -15,18 +14,19 @@ module Fusuma
15
14
  end
16
15
 
17
16
  def execute(event)
18
- search_command(event).tap do |command|
19
- break unless command
17
+ command = search_command(event)
20
18
 
21
- MultiLogger.info(command: command, args: event.record.args)
19
+ MultiLogger.info(command: command, args: event.record.args)
22
20
 
23
- additional_env = event.record.args
24
- .deep_transform_keys(&:to_s)
25
- .deep_transform_values { |v| (v * args_accel(event)).to_s }
21
+ accel = args_accel(event)
22
+ additional_env = event.record.args
23
+ .deep_transform_keys(&:to_s)
24
+ .deep_transform_values { |v| (v * accel).to_s }
26
25
 
27
- pid = POSIX::Spawn.spawn(additional_env, command.to_s)
28
- Process.detach(pid)
29
- end
26
+ pid = Process.spawn(additional_env, command.to_s)
27
+ Process.detach(pid)
28
+ rescue SystemCallError => e
29
+ MultiLogger.error("#{event.record.index.keys}": e.message.to_s)
30
30
  end
31
31
 
32
32
  def executable?(event)
@@ -25,6 +25,7 @@ module Fusuma
25
25
  warn "#{input.class.name}: #{e}"
26
26
  warn 'Send SIGKILL to fusuma processes'
27
27
  inputs.reject { |i| i == input }.each do |i|
28
+ warn "stop process: #{i.class.name.underscore}"
28
29
  Process.kill(:SIGKILL, i.pid)
29
30
  end
30
31
  exit 1
@@ -25,8 +25,9 @@ module Fusuma
25
25
  # @return [IO]
26
26
  def io
27
27
  @io ||= begin
28
- @pid, io = command.debug_events
29
- io
28
+ reader, writer = create_io
29
+ @pid = command.debug_events(writer)
30
+ reader
30
31
  end
31
32
  end
32
33
 
@@ -64,6 +65,12 @@ module Fusuma
64
65
  def list_devices_command
65
66
  config_params(:'libinput-list-devices')
66
67
  end
68
+
69
+ private
70
+
71
+ def create_io
72
+ IO.pipe
73
+ end
67
74
  end
68
75
  end
69
76
  end
@@ -21,8 +21,19 @@ module Fusuma
21
21
  def require_siblings_from_gems
22
22
  search_key = File.join(plugin_dir_name, '*.rb')
23
23
  Gem.find_latest_files(search_key).each do |siblings_plugin|
24
- if siblings_plugin =~ %r{fusuma-plugin-(.+).*/lib/#{plugin_dir_name}/\1_.+.rb}
24
+ next unless siblings_plugin =~ %r{fusuma-plugin-(.+).*/lib/#{plugin_dir_name}/\1_.+.rb}
25
+
26
+ match_data = siblings_plugin.match(%r{(.*)/(.*)/lib/(.*)})
27
+ gemspec_path = Dir.glob("#{match_data[1]}/#{match_data[2]}/*.gemspec").first
28
+ raise "Not Found: #{match_data[1]}/#{match_data[2]}/*.gemspec" unless gemspec_path
29
+
30
+ gemspec = Gem::Specification.load(gemspec_path)
31
+ fusuma_gemspec_path = File.expand_path('../../../fusuma.gemspec', __dir__)
32
+ fusuma_gemspec = Gem::Specification.load(fusuma_gemspec_path)
33
+ if gemspec.dependencies.find { |d| d.name == 'fusuma' }&.match?(fusuma_gemspec)
25
34
  require siblings_plugin
35
+ else
36
+ MultiLogger.warn "#{gemspec.name} #{gemspec.version} is incompatible with running #{fusuma_gemspec.name} #{fusuma_gemspec.version}"
26
37
  end
27
38
  end
28
39
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fusuma
4
- VERSION = '2.0.0.pre2'
4
+ VERSION = '2.0.4'
5
5
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tempfile'
4
+ require './lib/fusuma/config'
5
+
6
+ module Fusuma
7
+ module ConfigHelper
8
+ module_function
9
+
10
+ def load_config_yml=(string)
11
+ Config.custom_path = Tempfile.open do |temp_file|
12
+ temp_file.tap { |f| f.write(string) }
13
+ end
14
+ end
15
+
16
+ def clear_config_yml
17
+ Config.custom_path = nil
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require './lib/fusuma/config'
5
+ require './lib/fusuma/config/searcher'
6
+
7
+ # spec for Config
8
+ module Fusuma
9
+ RSpec.describe Config::Searcher do
10
+ let(:keymap) do
11
+ {
12
+ 'swipe' => {
13
+ 3 => {
14
+ 'left' => { 'command' => 'alt+Left' },
15
+ 'right' => { 'command' => 'alt+Right' }
16
+ },
17
+ 4 => {
18
+ 'left' => { 'command' => 'super+Left' },
19
+ 'right' => { 'command' => 'super+Right' }
20
+ }
21
+ },
22
+ 'pinch' => {
23
+ 'in' => { 'command' => 'ctrl+plus' },
24
+ 'out' => { 'command' => 'ctrl+minus' }
25
+ }
26
+ }
27
+ end
28
+
29
+ let(:keymap_without_finger) do
30
+ {
31
+ 'swipe' => {
32
+ 'left' => { 'command' => 'alt+Left' }
33
+ }
34
+ }
35
+ end
36
+
37
+ describe '.custom_path=' do
38
+ before { Singleton.__init__(Config) }
39
+ it 'should reload keymap file' do
40
+ keymap = Config.instance.keymap
41
+ Config.custom_path = './spec/lib/dummy_config.yml'
42
+ custom_keymap = Config.instance.keymap
43
+ expect(keymap).not_to eq custom_keymap
44
+ end
45
+ end
46
+
47
+ describe '.search' do
48
+ let(:index) { nil }
49
+ subject { Config::Searcher.new.search(index, location: keymap.deep_symbolize_keys) }
50
+ context 'index correct order' do
51
+ let(:index) { Config::Index.new %w[pinch in command] }
52
+ it { is_expected.to eq 'ctrl+plus' }
53
+ end
54
+
55
+ context 'index include skippable key' do
56
+ let(:index) do
57
+ Config::Index.new [
58
+ Config::Index::Key.new('pinch'),
59
+ Config::Index::Key.new(2, skippable: true),
60
+ Config::Index::Key.new('out'),
61
+ Config::Index::Key.new('command')
62
+ ]
63
+ end
64
+ it { expect(Config::Searcher.skip { subject }).to eq 'ctrl+minus' }
65
+ end
66
+
67
+ context 'index include skippable key at first' do
68
+ let(:index) do
69
+ Config::Index.new [
70
+ Config::Index::Key.new(:hoge, skippable: true),
71
+ Config::Index::Key.new(:fuga, skippable: true),
72
+ Config::Index::Key.new('pinch'),
73
+ Config::Index::Key.new('in'),
74
+ Config::Index::Key.new(:piyo, skippable: true),
75
+ Config::Index::Key.new('command')
76
+ ]
77
+ end
78
+ it { expect(Config::Searcher.skip { subject }).to eq 'ctrl+plus' }
79
+ end
80
+
81
+ context 'index incorrect order' do
82
+ let(:index) { Config::Index.new %w[in pinch 2 command] }
83
+ it { is_expected.not_to eq 'ctrl+plus' }
84
+ end
85
+ end
86
+
87
+ describe 'private_method: :cache' do
88
+ it 'should cache command' do
89
+ key = %w[event_type finger direction command].join(',')
90
+ value = 'shourtcut string'
91
+ searcher = Config::Searcher.new
92
+ searcher.send(:cache, key) { value }
93
+ expect(searcher.send(:cache, key)).to eq value
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require './lib/fusuma/config'
5
+
6
+ # spec for Config
7
+ module Fusuma
8
+ RSpec.describe Config do
9
+ let(:keymap) do
10
+ {
11
+ 'swipe' => {
12
+ 3 => {
13
+ 'left' => { 'command' => 'alt+Left' },
14
+ 'right' => { 'command' => 'alt+Right' }
15
+ },
16
+ 4 => {
17
+ 'left' => { 'command' => 'super+Left' },
18
+ 'right' => { 'command' => 'super+Right' }
19
+ }
20
+ },
21
+ 'pinch' => {
22
+ 'in' => { 'command' => 'ctrl+plus' },
23
+ 'out' => { 'command' => 'ctrl+minus' }
24
+ }
25
+ }
26
+ end
27
+
28
+ let(:keymap_without_finger) do
29
+ {
30
+ 'swipe' => {
31
+ 'left' => { 'command' => 'alt+Left' }
32
+ }
33
+ }
34
+ end
35
+
36
+ describe '.custom_path=' do
37
+ before { Singleton.__init__(Config) }
38
+ it 'should reload keymap file' do
39
+ keymap = Config.instance.keymap
40
+ Config.custom_path = './spec/lib/dummy_config.yml'
41
+ custom_keymap = Config.instance.keymap
42
+ expect(keymap).not_to eq custom_keymap
43
+ end
44
+ end
45
+
46
+ describe '#reload' do
47
+ before { Singleton.__init__(Config) }
48
+ it 'set Seacher' do
49
+ old = Config.instance.searcher
50
+ Config.instance.reload
51
+ expect(Config.instance.searcher).not_to eq(old)
52
+ end
53
+ end
54
+
55
+ describe '#validate' do
56
+ context 'with valid yaml' do
57
+ before do
58
+ string = <<~CONFIG
59
+ swipe:
60
+ 3:
61
+ left:
62
+ command: echo 'swipe left'
63
+
64
+ CONFIG
65
+ @file_path = Tempfile.open do |temp_file|
66
+ temp_file.tap { |f| f.write(string) }
67
+ end
68
+ end
69
+
70
+ it 'should return Hash' do
71
+ Config.instance.validate(@file_path)
72
+ end
73
+ end
74
+
75
+ context 'with invalid yaml' do
76
+ before do
77
+ string = <<~CONFIG
78
+ this is not yaml
79
+ CONFIG
80
+ @file_path = Tempfile.open do |temp_file|
81
+ temp_file.tap { |f| f.write(string) }
82
+ end
83
+ end
84
+
85
+ it 'raise InvalidFileError' do
86
+ expect { Config.instance.validate(@file_path) }.to raise_error(Config::InvalidFileError)
87
+ end
88
+
89
+ context 'with duplicated key' do
90
+ before do
91
+ string = <<~CONFIG
92
+ pinch:
93
+ 2:
94
+ in:
95
+ command: "xdotool keydown ctrl click 4 keyup ctrl" # threshold: 0.5, interval: 0.5
96
+ 2:
97
+ out:
98
+ command: "xdotool keydown ctrl click 5 keyup ctrl" # threshold: 0.5, interval: 0.5
99
+ CONFIG
100
+ @file_path = Tempfile.open do |temp_file|
101
+ temp_file.tap { |f| f.write(string) }
102
+ end
103
+ end
104
+
105
+ it 'raise InvalidFileError' do
106
+ expect { Config.instance.validate(@file_path) }.to raise_error(Config::InvalidFileError)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end