fusuma 1.11.1 → 2.0.2

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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +49 -7
  3. data/fusuma.gemspec +6 -16
  4. data/lib/fusuma.rb +91 -28
  5. data/lib/fusuma/config.rb +34 -62
  6. data/lib/fusuma/config/index.rb +39 -6
  7. data/lib/fusuma/config/searcher.rb +166 -0
  8. data/lib/fusuma/custom_process.rb +13 -0
  9. data/lib/fusuma/device.rb +22 -7
  10. data/lib/fusuma/environment.rb +6 -4
  11. data/lib/fusuma/hash_support.rb +40 -0
  12. data/lib/fusuma/libinput_command.rb +17 -21
  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 +46 -0
  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 -6
  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 +64 -8
  34. data/lib/fusuma/plugin/inputs/libinput_command_input.rb +19 -9
  35. data/lib/fusuma/plugin/inputs/timer_input.rb +63 -0
  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 +98 -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 +167 -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 +120 -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 +90 -167
  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 -37
  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 -6
  93. data/Rakefile +0 -15
@@ -12,15 +12,11 @@ module Fusuma
12
12
  attr_accessor :debug_mode
13
13
 
14
14
  def initialize
15
- super(STDOUT)
16
- @err_logger = Logger.new(STDERR)
15
+ super($stdout)
16
+ @err_logger = Logger.new($stderr)
17
17
  @debug_mode = false
18
18
  end
19
19
 
20
- def info(msg)
21
- super(msg)
22
- end
23
-
24
20
  def debug(msg)
25
21
  return unless debug_mode?
26
22
 
@@ -1,22 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './manager.rb'
4
- require_relative '../config.rb'
3
+ require_relative './manager'
4
+ require_relative '../config'
5
+ require_relative '../custom_process'
5
6
 
6
7
  module Fusuma
7
8
  module Plugin
8
9
  # Create a Plugin Class with extending this class
9
10
  class Base
11
+ include CustomProcess
10
12
  # when inherited from subclass
11
13
  def self.inherited(subclass)
14
+ super
12
15
  subclass_path = caller_locations(1..1).first.path
13
16
  Manager.add(plugin_class: subclass, plugin_path: subclass_path)
14
17
  end
15
18
 
16
- # get inherited classes
17
- # @example
18
- # [Vectors::Vector]
19
- # @return [Array]
19
+ # get subclasses
20
+ # @return [Array<Class>]
20
21
  def self.plugins
21
22
  Manager.plugins[name]
22
23
  end
@@ -33,19 +34,21 @@ module Fusuma
33
34
 
34
35
  return params unless key
35
36
 
36
- params.fetch(key, nil).tap do |val|
37
- next if val.nil?
37
+ @config_params ||= {}
38
+ @config_params["#{base.cache_key},#{key}"] ||=
39
+ params.fetch(key, nil).tap do |val|
40
+ next if val.nil?
38
41
 
39
- # NOTE: Type checking for config.yml
40
- param_types = Array(config_param_types.fetch(key))
42
+ # NOTE: Type checking for config.yml
43
+ param_types = Array(config_param_types.fetch(key))
41
44
 
42
- next if param_types.any? { |klass| val.is_a?(klass) }
45
+ next if param_types.any? { |klass| val.is_a?(klass) }
43
46
 
44
- MultiLogger.error('Please fix config.yml.')
45
- MultiLogger.error(":#{base.keys.map(&:symbol)
47
+ MultiLogger.error('Please fix config.yml.')
48
+ MultiLogger.error(":#{base.keys.map(&:symbol)
46
49
  .join(' => :')} => :#{key} should be #{param_types.join(' OR ')}.")
47
- exit 1
48
- end
50
+ exit 1
51
+ end
49
52
  end
50
53
 
51
54
  def config_index
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../base.rb'
3
+ require_relative '../base'
4
4
 
5
5
  module Fusuma
6
6
  module Plugin
@@ -8,6 +8,7 @@ module Fusuma
8
8
  # buffer events and output
9
9
  class Buffer < Base
10
10
  def initialize(*args)
11
+ super()
11
12
  @events = Array.new(*args)
12
13
  end
13
14
 
@@ -15,7 +16,7 @@ module Fusuma
15
16
 
16
17
  # @return [String]
17
18
  def type
18
- self.class.name.underscore.split('/').last.gsub('_buffer', '')
19
+ @type ||= self.class.name.underscore.split('/').last.gsub('_buffer', '')
19
20
  end
20
21
 
21
22
  # @param event [Event]
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './buffer.rb'
3
+ require_relative './buffer'
4
4
 
5
5
  module Fusuma
6
6
  module Plugin
@@ -8,17 +8,17 @@ module Fusuma
8
8
  # manage events and generate command
9
9
  class GestureBuffer < Buffer
10
10
  DEFAULT_SOURCE = 'libinput_gesture_parser'
11
- DEFAULT_SECONDS_TO_KEEP = 0.1
11
+ DEFAULT_SECONDS_TO_KEEP = 100
12
12
 
13
13
  def config_param_types
14
14
  {
15
- 'source': [String],
16
- 'seconds_to_keep': [Float, Integer]
15
+ source: [String],
16
+ seconds_to_keep: [Float, Integer]
17
17
  }
18
18
  end
19
19
 
20
20
  # @param event [Event]
21
- # @return [Buffer, false]
21
+ # @return [Buffer, FalseClass]
22
22
  def buffer(event)
23
23
  # TODO: buffering events into buffer plugins
24
24
  # - gesture event buffer
@@ -26,16 +26,13 @@ module Fusuma
26
26
  # - other event buffer
27
27
  return if event&.tag != source
28
28
 
29
- if bufferable?(event)
30
- @events.push(event)
31
- self
32
- else
33
- clear
34
- false
35
- end
29
+ @events.push(event)
30
+ self
36
31
  end
37
32
 
38
33
  def clear_expired(current_time: Time.now)
34
+ clear if ended?
35
+
39
36
  @seconds_to_keep ||= (config_params(:seconds_to_keep) || DEFAULT_SECONDS_TO_KEEP)
40
37
  @events.each do |e|
41
38
  break if current_time - e.time < @seconds_to_keep
@@ -46,17 +43,28 @@ module Fusuma
46
43
  end
47
44
  end
48
45
 
46
+ def ended?
47
+ return false if empty?
48
+
49
+ @events.last.record.status == 'end'
50
+ end
51
+
49
52
  # @param attr [Symbol]
50
53
  # @return [Float]
51
54
  def sum_attrs(attr)
52
- @events.map { |gesture_event| gesture_event.record.direction[attr].to_f }
53
- .inject(:+)
55
+ updating_events.map do |gesture_event|
56
+ gesture_event.record.delta[attr].to_f
57
+ end.inject(:+)
58
+ end
59
+
60
+ def updating_events
61
+ @events.select { |e| e.record.status == 'update' }
54
62
  end
55
63
 
56
64
  # @param attr [Symbol]
57
65
  # @return [Float]
58
66
  def avg_attrs(attr)
59
- sum_attrs(attr).to_f / @events.length
67
+ sum_attrs(attr).to_f / updating_events.length
60
68
  end
61
69
 
62
70
  # return [Integer]
@@ -76,20 +84,21 @@ module Fusuma
76
84
  @events.empty?
77
85
  end
78
86
 
79
- def select_by_events
80
- return enum_for(:select) unless block_given?
87
+ def select_by_events(&block)
88
+ return enum_for(:select_by_events) unless block_given?
81
89
 
82
- events = @events.select { |event| yield event }
90
+ events = @events.select(&block)
83
91
  self.class.new events
84
92
  end
85
93
 
86
- def bufferable?(event)
87
- case event.record.status
88
- when 'begin', 'end'
89
- false
90
- else
91
- true
92
- end
94
+ def select_from_last_begin
95
+ return self if empty?
96
+
97
+ index_from_last = @events.reverse.find_index { |e| e.record.status == 'begin' }
98
+ return GestureBuffer.new([]) if index_from_last.nil?
99
+
100
+ index_last_begin = events.length - index_from_last - 1
101
+ GestureBuffer.new(@events[index_last_begin..-1])
93
102
  end
94
103
  end
95
104
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './buffer'
4
+
5
+ module Fusuma
6
+ module Plugin
7
+ module Buffers
8
+ # manage events and generate command
9
+ class TimerBuffer < Buffer
10
+ DEFAULT_SOURCE = 'timer_input'
11
+ DEFAULT_SECONDS_TO_KEEP = 60
12
+
13
+ def config_param_types
14
+ {
15
+ source: [String],
16
+ seconds_to_keep: [Float, Integer]
17
+ }
18
+ end
19
+
20
+ # @param event [Event]
21
+ # @return [Buffer, NilClass]
22
+ def buffer(event)
23
+ return if event&.tag != source
24
+
25
+ @events.push(event)
26
+ self
27
+ end
28
+
29
+ def clear_expired(current_time: Time.now)
30
+ @seconds_to_keep ||= (config_params(:seconds_to_keep) || DEFAULT_SECONDS_TO_KEEP)
31
+ @events.each do |e|
32
+ break if current_time - e.time < @seconds_to_keep
33
+
34
+ MultiLogger.debug("#{self.class.name}##{__method__}")
35
+
36
+ @events.delete(e)
37
+ end
38
+ end
39
+
40
+ def empty?
41
+ @events.empty?
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,13 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../base.rb'
4
- require_relative '../events/event.rb'
3
+ require_relative '../base'
4
+ require_relative '../events/event'
5
5
 
6
6
  module Fusuma
7
7
  module Plugin
8
8
  module Detectors
9
9
  # Inherite this base
10
10
  class Detector < Base
11
+ # @return [Array<String>]
12
+ def sources
13
+ @source ||= self.class.const_get('SOURCES')
14
+ end
15
+
16
+ # Always watch buffers and detect them or not
17
+ # @return [TrueClass,FalseClass]
18
+ def watch?
19
+ false
20
+ end
21
+
11
22
  # @param _buffers [Array<Buffer>]
12
23
  # @return [Event] if event is detected
13
24
  # @return [NilClass] if event is NOT detected
@@ -21,7 +32,7 @@ module Fusuma
21
32
  # @return [Events::Event]
22
33
  def create_event(record:)
23
34
  @last_time = Time.now
24
- Events::Event.new(time: Time.now, tag: tag, record: record)
35
+ Events::Event.new(time: @last_time, tag: tag, record: record)
25
36
  end
26
37
 
27
38
  def last_time
@@ -33,11 +44,21 @@ module Fusuma
33
44
  end
34
45
 
35
46
  def tag
36
- self.class.name.split('Detectors::').last.underscore
47
+ self.class.tag
37
48
  end
38
49
 
39
50
  def type
40
- self.class.name.underscore.split('/').last.gsub('_detector', '')
51
+ self.class.type
52
+ end
53
+
54
+ class << self
55
+ def tag
56
+ name.split('Detectors::').last.underscore
57
+ end
58
+
59
+ def type(tag_name = tag)
60
+ tag_name.gsub('_detector', '')
61
+ end
41
62
  end
42
63
  end
43
64
  end
@@ -1,50 +1,111 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './detector.rb'
3
+ require_relative './detector'
4
4
 
5
5
  module Fusuma
6
6
  module Plugin
7
7
  module Detectors
8
8
  class PinchDetector < Detector
9
+ SOURCES = ['gesture'].freeze
9
10
  BUFFER_TYPE = 'gesture'
10
11
  GESTURE_RECORD_TYPE = 'pinch'
11
12
 
12
13
  FINGERS = [2, 3, 4].freeze
13
- BASE_THERESHOLD = 0.1
14
- BASE_INTERVAL = 0.1
14
+ BASE_THERESHOLD = 1.3
15
15
 
16
16
  # @param buffers [Array<Buffer>]
17
- # @return [Event] if event is detected
17
+ # @return [Events::Event] if event is detected
18
18
  # @return [NilClass] if event is NOT detected
19
19
  def detect(buffers)
20
- buffer = buffers.find { |b| b.type == BUFFER_TYPE }
21
- .select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE }
22
-
23
- return if buffer.empty?
24
-
25
- finger = buffer.finger
26
-
27
- avg_zoom = buffer.avg_attrs(:zoom)
28
- first_zoom = buffer.events.first.record.direction.zoom
29
- diameter = avg_zoom / first_zoom
30
-
31
- direction = Direction.new(diameter: diameter).to_s
32
- quantity = Quantity.new(diameter: diameter).to_f
33
-
34
- index = create_index(gesture: type,
35
- finger: finger,
36
- direction: direction)
37
-
38
- return unless enough?(index: index, quantity: quantity)
20
+ gesture_buffer = buffers.find { |b| b.type == BUFFER_TYPE }
21
+ .select_from_last_begin
22
+ .select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE }
23
+
24
+ updating_events = gesture_buffer.updating_events
25
+ return if updating_events.empty?
26
+
27
+ finger = gesture_buffer.finger
28
+
29
+ status = case gesture_buffer.events.last.record.status
30
+ when 'end'
31
+ 'end'
32
+ when 'update'
33
+ if updating_events.length == 1
34
+ 'begin'
35
+ else
36
+ 'update'
37
+ end
38
+ else
39
+ gesture_buffer.events.last.record.status
40
+ end
41
+
42
+ prev_event, event = if status == 'end'
43
+ [
44
+ gesture_buffer.events[-3],
45
+ gesture_buffer.events[-2]
46
+ ]
47
+ else
48
+ [
49
+ gesture_buffer.events[-2],
50
+ gesture_buffer.events[-1]
51
+ ]
52
+ end
53
+ delta = event.record.delta
54
+ prev_delta = prev_event.record.delta
55
+
56
+ repeat_direction = Direction.new(target: delta.zoom, base: (prev_delta&.zoom || 1.0)).to_s
57
+ # repeat_quantity = Quantity.new(target: delta.zoom, base: (prev_delta&.zoom || 1.0)).to_f
58
+
59
+ repeat_index = create_repeat_index(gesture: type, finger: finger,
60
+ direction: repeat_direction,
61
+ status: status)
62
+ if status == 'update'
63
+ return unless moved?(prev_event, event)
64
+
65
+ avg_zoom = gesture_buffer.avg_attrs(:zoom)
66
+ first_zoom = updating_events.first.record.delta.zoom
67
+
68
+ oneshot_quantity = Quantity.new(target: avg_zoom, base: first_zoom).to_f
69
+ oneshot_direction = Direction.new(target: avg_zoom, base: first_zoom).to_s
70
+ oneshot_index = create_oneshot_index(gesture: type, finger: finger,
71
+ direction: oneshot_direction)
72
+ if enough_oneshot_threshold?(index: oneshot_index, quantity: oneshot_quantity)
73
+ return [
74
+ create_event(record: Events::Records::IndexRecord.new(
75
+ index: oneshot_index, trigger: :oneshot, args: delta.to_h
76
+ )),
77
+ create_event(record: Events::Records::IndexRecord.new(
78
+ index: repeat_index, trigger: :repeat, args: delta.to_h
79
+ ))
80
+ ]
81
+ end
82
+ end
83
+ create_event(record: Events::Records::IndexRecord.new(
84
+ index: repeat_index, trigger: :repeat, args: delta.to_h
85
+ ))
86
+ end
39
87
 
40
- create_event(record: Events::Records::IndexRecord.new(index: index))
88
+ # @param [String] gesture
89
+ # @param [Integer] finger
90
+ # @param [String] direction
91
+ # @param [String] status
92
+ # @return [Config::Index]
93
+ def create_repeat_index(gesture:, finger:, direction:, status:)
94
+ Config::Index.new(
95
+ [
96
+ Config::Index::Key.new(gesture),
97
+ Config::Index::Key.new(finger.to_i),
98
+ Config::Index::Key.new(direction, skippable: true),
99
+ Config::Index::Key.new(status)
100
+ ]
101
+ )
41
102
  end
42
103
 
43
104
  # @param [String] gesture
44
105
  # @param [Integer] finger
45
106
  # @param [String] direction
46
107
  # @return [Config::Index]
47
- def create_index(gesture:, finger:, direction:)
108
+ def create_oneshot_index(gesture:, finger:, direction:)
48
109
  Config::Index.new(
49
110
  [
50
111
  Config::Index::Key.new(gesture),
@@ -56,41 +117,25 @@ module Fusuma
56
117
 
57
118
  private
58
119
 
59
- def enough?(index:, quantity:)
60
- enough_interval?(index: index) && enough_diameter?(index: index, quantity: quantity)
120
+ def moved?(prev_event, event)
121
+ zoom_delta = (event.record.delta.zoom - prev_event.record.delta.zoom).abs
122
+ updating_time = (event.time - prev_event.time) * 100
123
+ zoom_delta / updating_time > 0.01
61
124
  end
62
125
 
63
- def enough_diameter?(index:, quantity:)
126
+ def enough_oneshot_threshold?(index:, quantity:)
64
127
  quantity >= threshold(index: index)
65
128
  end
66
129
 
67
- def enough_interval?(index:)
68
- return true if first_time?
69
- return true if (Time.now - last_time) > interval_time(index: index)
70
-
71
- false
72
- end
73
-
74
130
  def threshold(index:)
75
131
  @threshold ||= {}
76
132
  @threshold[index.cache_key] ||= begin
77
- keys_specific = Config::Index.new [*index.keys, 'threshold']
78
- keys_global = Config::Index.new ['threshold', type]
79
- config_value = Config.search(keys_specific) ||
80
- Config.search(keys_global) || 1
81
- BASE_THERESHOLD * config_value
82
- end
83
- end
84
-
85
- def interval_time(index:)
86
- @interval_time ||= {}
87
- @interval_time[index.cache_key] ||= begin
88
- keys_specific = Config::Index.new [*index.keys, 'interval']
89
- keys_global = Config::Index.new ['interval', type]
90
- config_value = Config.search(keys_specific) ||
91
- Config.search(keys_global) || 1
92
- BASE_INTERVAL * config_value
93
- end
133
+ keys_specific = Config::Index.new [*index.keys, 'threshold']
134
+ keys_global = Config::Index.new ['threshold', type]
135
+ config_value = Config.search(keys_specific) ||
136
+ Config.search(keys_global) || 1
137
+ BASE_THERESHOLD * config_value
138
+ end
94
139
  end
95
140
 
96
141
  # direction of gesture
@@ -98,8 +143,9 @@ module Fusuma
98
143
  IN = 'in'
99
144
  OUT = 'out'
100
145
 
101
- def initialize(diameter:)
102
- @diameter = diameter
146
+ def initialize(target:, base:)
147
+ @target = target.to_f
148
+ @base = base.to_f
103
149
  end
104
150
 
105
151
  def to_s
@@ -107,7 +153,7 @@ module Fusuma
107
153
  end
108
154
 
109
155
  def calc
110
- if @diameter > 1
156
+ if @target > @base
111
157
  IN
112
158
  else
113
159
  OUT
@@ -117,8 +163,9 @@ module Fusuma
117
163
 
118
164
  # quantity of gesture
119
165
  class Quantity
120
- def initialize(diameter:)
121
- @diameter = diameter
166
+ def initialize(target:, base:)
167
+ @target = target.to_f
168
+ @base = base.to_f
122
169
  end
123
170
 
124
171
  def to_f
@@ -126,7 +173,11 @@ module Fusuma
126
173
  end
127
174
 
128
175
  def calc
129
- (1.0 - @diameter).abs
176
+ if @target > @base
177
+ @target / @base
178
+ else
179
+ @base / @target
180
+ end
130
181
  end
131
182
  end
132
183
  end