rmonitor 1.0.1 → 2.0.0

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +49 -40
  4. data/bin/rmonitor +38 -100
  5. data/lib/rmonitor.rb +17 -20
  6. data/lib/rmonitor/actions.rb +30 -0
  7. data/lib/rmonitor/actions/builder.rb +15 -0
  8. data/lib/rmonitor/actions/dsl.rb +23 -0
  9. data/lib/rmonitor/cache.rb +12 -0
  10. data/lib/rmonitor/capabilities.rb +38 -0
  11. data/lib/rmonitor/capabilities/builder.rb +15 -0
  12. data/lib/rmonitor/capabilities/dsl.rb +15 -0
  13. data/lib/rmonitor/commands/cl/base.rb +13 -0
  14. data/lib/rmonitor/commands/cl/invoke.rb +22 -0
  15. data/lib/rmonitor/commands/cl/list.rb +43 -0
  16. data/lib/rmonitor/commands/cl/update.rb +20 -0
  17. data/lib/rmonitor/commands/invoke.rb +23 -0
  18. data/lib/rmonitor/commands/list.rb +13 -0
  19. data/lib/rmonitor/commands/update.rb +18 -0
  20. data/lib/rmonitor/config.rb +27 -0
  21. data/lib/rmonitor/config/builder.rb +21 -0
  22. data/lib/rmonitor/config/dsl.rb +25 -0
  23. data/lib/rmonitor/invoker.rb +9 -0
  24. data/lib/rmonitor/matcher.rb +32 -0
  25. data/lib/rmonitor/profile/builder.rb +15 -0
  26. data/lib/rmonitor/profile/dsl.rb +15 -0
  27. data/lib/rmonitor/selector.rb +14 -0
  28. data/lib/rmonitor/strategies/base.rb +10 -0
  29. data/lib/rmonitor/strategies/optimistic.rb +15 -0
  30. data/lib/rmonitor/strategies/pessimistic.rb +17 -0
  31. data/lib/rmonitor/transformer.rb +38 -0
  32. data/lib/rmonitor/version.rb +1 -1
  33. data/lib/rmonitor/xrandr.rb +16 -0
  34. data/test/actions/builder_test.rb +27 -0
  35. data/test/actions_test.rb +60 -0
  36. data/test/cache_test.rb +30 -0
  37. data/test/capabilities/builder_test.rb +23 -0
  38. data/test/capabilities_test.rb +114 -0
  39. data/test/commands/cl/invoke_test.rb +38 -0
  40. data/test/commands/cl/list_test.rb +36 -0
  41. data/test/commands/cl/update_test.rb +24 -0
  42. data/test/commands/invoke_test.rb +86 -0
  43. data/test/commands/list_test.rb +50 -0
  44. data/test/commands/update_test.rb +67 -0
  45. data/test/config/builder_test.rb +51 -0
  46. data/test/config_test.rb +68 -0
  47. data/test/matcher_test.rb +90 -0
  48. data/test/profile/builder_test.rb +26 -0
  49. data/test/selector_test.rb +30 -0
  50. data/test/strategies/optimistic_test.rb +24 -0
  51. data/test/strategies/pessimistic_test.rb +26 -0
  52. data/test/test_helper.rb +19 -0
  53. data/test/transformer_test.rb +159 -0
  54. data/test/xrandr_test.rb +76 -0
  55. metadata +178 -28
  56. data/.rspec +0 -1
  57. data/Gemfile +0 -3
  58. data/Gemfile.lock +0 -24
  59. data/lib/rmonitor/devices.rb +0 -29
  60. data/lib/rmonitor/helpers/dsl_helpers.rb +0 -38
  61. data/lib/rmonitor/helpers/profile_helpers.rb +0 -48
  62. data/lib/rmonitor/helpers/xrandr_read_helpers.rb +0 -75
  63. data/lib/rmonitor/helpers/xrandr_write_helpers.rb +0 -55
  64. data/lib/rmonitor/profiles.rb +0 -51
  65. data/rmonitor.gemspec +0 -44
  66. data/spec/lib/helpers/dsl_helper_spec.rb +0 -29
  67. data/spec/lib/helpers/profile_helpers_spec.rb +0 -138
  68. data/spec/lib/helpers/xrandr_read_helpers_spec.rb +0 -259
  69. data/spec/lib/helpers/xrandr_write_helpers_spec.rb +0 -158
  70. data/spec/support/device_helper.rb +0 -3
  71. data/spec/support/profile_helper.rb +0 -3
  72. data/spec/support/string_helpers.rb +0 -25
@@ -0,0 +1,15 @@
1
+ require "rmonitor/capabilities/dsl"
2
+
3
+ class RMonitor
4
+ class Capabilities
5
+ class Builder
6
+ class << self
7
+ def define(&block)
8
+ dsl = RMonitor::Capabilities::DSL.new
9
+ dsl.instance_eval(&block)
10
+ dsl.capabilities
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class RMonitor
2
+ class Capabilities
3
+ class DSL
4
+ attr_accessor :capabilities
5
+
6
+ def initialize
7
+ @capabilities = []
8
+ end
9
+
10
+ def device(name, options = {})
11
+ @capabilities << options.merge(:name => name)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ class RMonitor
2
+ module Commands
3
+ module CL
4
+ class Base
5
+ def initialize(options = {})
6
+ @options = options
7
+ @out = options[:out] || $stdout
8
+ @err = options[:err] || $stderr
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ require "rmonitor/commands/invoke"
2
+
3
+ class RMonitor
4
+ module Commands
5
+ module CL
6
+ class Invoke
7
+ def initialize(options = {})
8
+ @err = options[:err] || $stderr
9
+ @invoke = options[:invoke] || RMonitor::Commands::Invoke.new(options)
10
+ end
11
+
12
+ def execute(name)
13
+ @invoke.execute(name)
14
+ rescue RMonitor::UnknownProfileError
15
+ @err.puts "unknown profile"
16
+ rescue RMonitor::UninvokableProfileError
17
+ @err.puts "profile is not invokable"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,43 @@
1
+ require "rmonitor/commands/list"
2
+
3
+ class RMonitor
4
+ module Commands
5
+ module CL
6
+ class List
7
+ def initialize(options = {})
8
+ @out = options[:out] || $stdout
9
+ @list = options[:list] || RMonitor::Commands::List.new(options)
10
+ @matcher = options[:matcher] || RMonitor::Matcher.new(options)
11
+ end
12
+
13
+ def execute
14
+ profiles = @list.execute
15
+
16
+ profiles.each do |profile|
17
+ @out.write("#{profile[:name]}\t")
18
+
19
+ if @matcher.invokable?(profile)
20
+ @out.write("invokable")
21
+ else
22
+ @out.write("uninvokable")
23
+ end
24
+
25
+ profile[:devices].each do |device|
26
+ @out.write("\t#{device[:name]}")
27
+
28
+ if device[:mode] && device[:rate]
29
+ @out.write(" (#{device[:mode]} #{device[:rate]})")
30
+ elsif device[:mode]
31
+ @out.write(" (#{device[:mode]})")
32
+ elsif device[:rate]
33
+ @out.write(" (#{device[:rate]})")
34
+ end
35
+ end
36
+
37
+ @out.write("\n")
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,20 @@
1
+ require "rmonitor/commands/update"
2
+
3
+ class RMonitor
4
+ module Commands
5
+ module CL
6
+ class Update
7
+ def initialize(options = {})
8
+ @err = options[:err] || $stderr
9
+ @update = options[:update] || RMonitor::Commands::Update.new(options)
10
+ end
11
+
12
+ def execute
13
+ @update.execute
14
+ rescue RMonitor::NoInvokableProfileError
15
+ @err.puts "no invokable profile"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ class RMonitor
2
+ module Commands
3
+ class Invoke
4
+ def initialize(options = {})
5
+ @profiles = options[:profiles] || Config.new.profiles
6
+ @matcher = options[:matcher] || Matcher.new(options)
7
+ @strategy = options[:strategy] || Strategies::Pessimistic.new(options)
8
+ @factory = options[:factory] || Actions.new(options)
9
+ end
10
+
11
+ def execute(name)
12
+ profile = @profiles.find { |p| p[:name] == name }
13
+
14
+ raise UnknownProfileError unless profile
15
+ raise UninvokableProfileError unless @matcher.invokable?(profile)
16
+
17
+ actions = @factory.create(profile)
18
+
19
+ @strategy.execute(actions)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ class RMonitor
2
+ module Commands
3
+ class List
4
+ def initialize(options = {})
5
+ @profiles = options[:profiles] || Config.new.profiles
6
+ end
7
+
8
+ def execute
9
+ @profiles
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ class RMonitor
2
+ module Commands
3
+ class Update
4
+ def initialize(options = {})
5
+ @invoke = options[:invoke] || Invoke.new(options)
6
+ @selector = options[:selector] || Selector.new(options)
7
+ end
8
+
9
+ def execute
10
+ profile = @selector.first_invokable
11
+
12
+ raise NoInvokableProfileError unless profile
13
+
14
+ @invoke.execute(profile[:name])
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ require "rmonitor/config/builder"
2
+
3
+ class RMonitor
4
+ class Config
5
+ def profiles
6
+ Builder.define read
7
+ end
8
+
9
+ def read
10
+ File.read self.class.config_path
11
+ end
12
+
13
+ class << self
14
+ attr_writer :config_path
15
+
16
+ def config_path
17
+ @config_path || default_config_path
18
+ end
19
+
20
+ private
21
+
22
+ def default_config_path
23
+ File.join(Dir.home, ".config", "rmonitor", "config.rb")
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ require "rmonitor/config/dsl"
2
+
3
+ class RMonitor
4
+ class Config
5
+ class Builder
6
+ class << self
7
+ def define(input = nil, &block)
8
+ dsl = RMonitor::Config::DSL.new
9
+
10
+ if input
11
+ dsl.instance_eval(input)
12
+ else
13
+ dsl.instance_eval(&block)
14
+ end
15
+
16
+ dsl.profiles
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ require "rmonitor/profile/builder"
2
+
3
+ class RMonitor
4
+ class Config
5
+ class DSL
6
+ attr_accessor :profiles
7
+
8
+ def initialize
9
+ @profiles = []
10
+ end
11
+
12
+ def profile(name, options = {}, &block)
13
+ @profiles << RMonitor::Profile::Builder.define(name, options, &block)
14
+
15
+ if @profiles.last.has_key?(:only_if)
16
+ @profiles.last[:only_if] = method(@profiles.last[:only_if])
17
+ end
18
+
19
+ if @profiles.last.has_key?(:not_if)
20
+ @profiles.last[:not_if] = method(@profiles.last[:not_if])
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ class RMonitor
2
+ class Invoker
3
+ def initialize(*); end
4
+
5
+ def invoke(command)
6
+ Kernel.`(command)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ class RMonitor
2
+ class Matcher
3
+ def initialize(options = {})
4
+ @capabilities = options[:capabilities] || Capabilities.new(options).parse
5
+ end
6
+
7
+ def invokable?(profile)
8
+ return false if profile.has_key?(:only_if) && !profile[:only_if].call
9
+ return false if profile.has_key?(:not_if) && profile[:not_if].call
10
+
11
+ profile[:devices].all? do |device|
12
+ has_desired_capability? device
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def has_desired_capability?(desire)
19
+ @capabilities.any? do |capability|
20
+ match_desire_capability?(desire, capability)
21
+ end
22
+ end
23
+
24
+ def match_desire_capability?(desire, capability)
25
+ return false if desire[:name] != capability[:name]
26
+ return false if desire[:mode] && desire[:mode] != capability[:mode]
27
+ return false if desire[:rate] && desire[:rate] != capability[:rate]
28
+
29
+ true
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ require "rmonitor/profile/dsl"
2
+
3
+ class RMonitor
4
+ module Profile
5
+ class Builder
6
+ class << self
7
+ def define(name, options = {}, &block)
8
+ dsl = RMonitor::Profile::DSL.new
9
+ dsl.instance_eval &block
10
+ options.merge :name => name, :devices => dsl.devices
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class RMonitor
2
+ module Profile
3
+ class DSL
4
+ attr_accessor :devices
5
+
6
+ def initialize
7
+ @devices = []
8
+ end
9
+
10
+ def device(name, options = {})
11
+ @devices << options.merge(:name => name)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ class RMonitor
2
+ class Selector
3
+ def initialize(options = {})
4
+ @profiles = options[:profiles] || Config.new.profiles
5
+ @matcher = options[:matcher] || Matcher.new(options)
6
+ end
7
+
8
+ def first_invokable
9
+ @profiles.find do |profile|
10
+ @matcher.invokable? profile
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ class RMonitor
2
+ module Strategies
3
+ class Base
4
+ def initialize(options = {})
5
+ @xrandr = options[:xrandr] || XRandR.new(options)
6
+ @transformer = options[:transformer] || Transformer.new
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ require "rmonitor/strategies/base"
2
+
3
+ class RMonitor
4
+ module Strategies
5
+ class Optimistic < Base
6
+ def execute(actions)
7
+ transformations = actions.map do |action|
8
+ @transformer.transform(action)
9
+ end
10
+
11
+ @xrandr.invoke(*transformations.flatten)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ require "rmonitor/strategies/base"
2
+
3
+ class RMonitor
4
+ module Strategies
5
+ class Pessimistic < Base
6
+ def execute(actions)
7
+ transformations = actions.map do |action|
8
+ @transformer.transform(action)
9
+ end
10
+
11
+ transformations.each do |transformation|
12
+ @xrandr.invoke(*transformation)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,38 @@
1
+ class RMonitor
2
+ class Transformer
3
+ def transform(action)
4
+ case action.delete(:action)
5
+ when :off
6
+ transform_off(action)
7
+ when :on
8
+ transform_on(action)
9
+ when :option
10
+ transforn_option(action)
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def transform_on(action)
17
+ args = ["--output", action.delete(:name)]
18
+
19
+ action.each do |key, value|
20
+ args << "--#{key.to_s.gsub("_", "-")}"
21
+
22
+ unless value.is_a?(TrueClass)
23
+ args << value.to_s
24
+ end
25
+ end
26
+
27
+ args
28
+ end
29
+
30
+ def transform_off(action)
31
+ ["--output", action.delete(:name), "--off"]
32
+ end
33
+
34
+ def transforn_option(action)
35
+ ["--#{action[:name].to_s.gsub("_", "-")}", action[:value].to_s]
36
+ end
37
+ end
38
+ end