From 7617ae8be7fd75eb1f28c439e8a3f478ef4b0762 Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Sun, 10 Apr 2016 22:41:17 +0100 Subject: [PATCH 01/21] Added BBCWeather Block --- README.md | 23 +++++++++++ barr.gemspec | 3 ++ exe/barr_open_url | 6 +++ lib/barr.rb | 4 ++ lib/barr/block.rb | 46 ++++++++++++++++++++-- lib/barr/blocks/bbc_weather.rb | 27 +++++++++++++ lib/barr/controller.rb | 38 +++++++++++++++++++ lib/barr/controllers/bbc_weather.rb | 59 +++++++++++++++++++++++++++++ lib/barr/manager.rb | 29 ++++++++++++++ spec/block_spec.rb | 22 +++++++++++ spec/blocks/bbc_weather_spec.rb | 29 ++++++++++++++ spec/mocks/bbc_weather.rb | 39 +++++++++++++++++++ 12 files changed, 322 insertions(+), 3 deletions(-) create mode 100755 exe/barr_open_url create mode 100644 lib/barr/blocks/bbc_weather.rb create mode 100644 lib/barr/controller.rb create mode 100644 lib/barr/controllers/bbc_weather.rb create mode 100644 spec/blocks/bbc_weather_spec.rb create mode 100644 spec/mocks/bbc_weather.rb diff --git a/README.md b/README.md index 7275ee1..18ffa07 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,29 @@ Show battery status. | --- | --- | --- | --- | | `show_remaining` | bool | Show the remaining battery time | `true` | +#### BBCWeather + +Shows configurable weather information as provided by the BBC. Recommended over the `Temperature` block due to how much more reliable the BBC service is. + +`bbc = Barr::Blocks::BBCWeather.new location: "5308655", format: "${TEMPERATURE} wind: ${WINDSPEED} ${WINDDIRECTION}" + +| Option | Value | Description | Default | +| --- | --- | --- | --- | +| `format` | string | Configurable format for showing which weather information is displayed. See table below for options. | `"${TEMPERATURE} - ${SUMMARY}"` | +| `location` | string | Find your location on the [BBC Weather](http://www.bbc.co.uk/weather) service and use the last part of the URL as the location string. For example, Phoenix Arizona is "5308655". | **REQUIRED** | +| `speed_unit` | "mph" or "kph" | Whether to show speeds in mph or kph | `"mph"` +| `temp_unit` | "c" or "f" | Whether to show temperatures in C or F | `"c"` + +| Option | Description | +| --- | --- | +| `${TEMPERATURE}` | Current temperature | +| `${SUMMARY}` | Brief summary of weather, e.g. "Light cloud" | +| `${WINDSPEED}` | Current wind speed | +| `${WINDDIRECTION}` | Current wind direction | +| `${HUMIDITY}` | Current humidity percentage | +| `${VISIBILITY}` | Sumamry of visbility, e.g. "Excellent" | +| `${PRESSURE}` | Current pressure and trend, e.g. "1000mb, Falling" | + #### Bspwm (Experimental) **Requires Bspwm**. Shows desktops for selected monitor. and highlights focused one. Unfocused desktops are clickable. Could do with some optimization work and feedback from people that use BSP frequently, especially with multiple monitors. diff --git a/barr.gemspec b/barr.gemspec index ddec6fd..e48a42a 100644 --- a/barr.gemspec +++ b/barr.gemspec @@ -29,12 +29,15 @@ Gem::Specification.new do |spec| spec.add_development_dependency "rake", "~> 10.0" spec.add_development_dependency "rspec", "~> 3.0" spec.add_development_dependency "timecop", "~> 0.8.0" + spec.add_development_dependency "pry", "~> 0.10" spec.add_runtime_dependency "i3ipc", "0.2.0" spec.add_runtime_dependency "weather-api", "1.2.0" + spec.add_runtime_dependency "nokogiri", "~> 1.6" spec.requirements << "Lemonbar with XFT support (https://github.com/krypt-n/bar)" spec.requirements << "(Optional) I3 for Workspace support" + spec.requirements << "(Optional) Bspwm for Bspwm desktop support" spec.requirements << "(Optional) RhythmBox & rhythmbox-client" spec.requirements << "(Optional) FontAwesome font" end diff --git a/exe/barr_open_url b/exe/barr_open_url new file mode 100755 index 0000000..40ef241 --- /dev/null +++ b/exe/barr_open_url @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby + +require 'rubygems' + +cmd = ARGV.join('://').gsub("\\","") +`xdg-open #{cmd}` diff --git a/lib/barr.rb b/lib/barr.rb index ba862e2..81c94f1 100644 --- a/lib/barr.rb +++ b/lib/barr.rb @@ -1,8 +1,10 @@ require 'barr/version' require 'barr/manager' require 'barr/block' +require 'barr/controller' require 'barr/blocks/battery' +require 'barr/blocks/bbc_weather' require 'barr/blocks/bspwm' require 'barr/blocks/clock' require 'barr/blocks/conky' @@ -17,5 +19,7 @@ require 'barr/blocks/whoami' require 'barr/blocks/separator' +require 'barr/controllers/bbc_weather' + module Barr end diff --git a/lib/barr/block.rb b/lib/barr/block.rb index 700def2..b4b4539 100644 --- a/lib/barr/block.rb +++ b/lib/barr/block.rb @@ -1,7 +1,6 @@ module Barr class Block - attr_reader :align, :bgcolor, :fgcolor, :icon, :interval, :output - attr_accessor :manager + attr_accessor :align, :bgcolor, :fgcolor, :icon, :interval, :manager, :controller, :format, :output def initialize(opts = {}) reassign_deprecated_option opts, :fcolor, :fgcolor @@ -16,6 +15,10 @@ def initialize(opts = {}) @output = '' end + def config + # called by manager + end + def <<(str) @output << str end @@ -35,10 +38,47 @@ def update! end def tmp_filename - @tmp_filename ||= "/tmp/#{SecureRandom.uuid}-#{self.class.name.gsub(/::/, "-")}-#{SecureRandom.urlsafe_base64}" + @tmp_filename ||= "/tmp/barr-#{SecureRandom.uuid}-#{self.class.name.gsub(/::/, "-")}-#{SecureRandom.urlsafe_base64}" return @tmp_filename end + def substitue_variables string_format, subs + reg = /\$\{\w+\}/i + new_string = string_format + matches = string_format.scan reg + matches.each do |match| + keyword = match.scan(/\w+/i).first.downcase + + if subs.has_key? keyword + sub = keyword + else + sub = "" + end + + new_string.gsub!(match, sub) + end + + return new_string + end + + def format_string_from_hash(hash) + formatted = @format.clone + matches = @format.scan(/([\$][\{](\w+)[\}])/) + + matches.each do |match| + key = match[1].downcase.to_sym + if hash.has_key? key + sub = hash[key] + else + sub = "" + end + + formatted.gsub! match[0], sub + end + + return formatted + end + # Backwards compatiblity methods. # can't use alias/alias_method as they don't # trickle down to subclasses diff --git a/lib/barr/blocks/bbc_weather.rb b/lib/barr/blocks/bbc_weather.rb new file mode 100644 index 0000000..4ee207d --- /dev/null +++ b/lib/barr/blocks/bbc_weather.rb @@ -0,0 +1,27 @@ +module Barr + module Blocks + class BBCWeather < Block + attr_accessor :location + + def initialize opts={} + super + @location = opts[:location] + @format = opts[:format] || "${TEMPERATURE} - ${SUMMARY}" + @temp_unit = opts[:temp_unit] || "c" + @speed_unit = opts[:speed_unit] || "mph" + end + + def config + opts = {id: @location, temp_unit: @temp_unit, speed_unit: @speed_unit } + @controller = @manager.controller :BBCWeather, opts + end + + def update! + op = @controller.output + @output = "%{A:barr_open_url http www.bbc.co.uk\/weather\/#{@location}:}#{format_string_from_hash(op)}%{A}" + end + + + end + end +end diff --git a/lib/barr/controller.rb b/lib/barr/controller.rb new file mode 100644 index 0000000..d96aed5 --- /dev/null +++ b/lib/barr/controller.rb @@ -0,0 +1,38 @@ +module Barr + class Controller + attr_accessor :file, :output, :retry_at, :interval, :id + + def initialize opts={} + @id = opts[:id] + @interval = opts[:interval] || 5 + @interval = (@interval * 10).round + @output = {} + end + + def run! + end + + def update! + + end + + def file + @file ||= File.new(filename, "w" ) + end + + def filename + @filename ||= "/tmp/barr-#{self.class.name}-#{@id}".gsub("::","-").downcase + end + + def close_file + @file.close + @file.unlink + @file = nil + end + + def destroy! + close_file + end + + end +end diff --git a/lib/barr/controllers/bbc_weather.rb b/lib/barr/controllers/bbc_weather.rb new file mode 100644 index 0000000..bb78f68 --- /dev/null +++ b/lib/barr/controllers/bbc_weather.rb @@ -0,0 +1,59 @@ +require 'nokogiri' +require 'open-uri' +require 'json' +require 'pry' + +module Barr + module Controllers + class BBCWeather < Controller + + def initialize opts={} + super + @temp_unit = (opts[:temp_unit] || "c").downcase + @speed_unit = (opts[:speed_unit] || "mph").downcase + end + + def update! + @output = JSON.parse(`cat #{filename}`, symbolize_names: true) + end + + def run! + @thread = Thread.new do + loop do + begin + url = "http://www.bbc.co.uk/weather/#{@id}" + + op = {} + + noko = Nokogiri::HTML(open(url)) + + op[:temperature] = noko.css("div.observationsRecord span.units-value.temperature-value.temperature-value-unit-#{@temp_unit}").text + op[:summary] = noko.css("div.observationsRecord p.weather-type img").attribute("alt").value + op[:windspeed] = noko.css("div.observationsRecord span.speed span.units-values.windspeed-units-values span.windspeed-value-unit-#{@speed_unit}").text + op[:winddirection] = noko.css("div.observationsRecord p.wind-speed span.wind.wind-speed").attribute("data-tooltip-mph").value.split(", ")[1] + op[:humidity] = noko.css("div.observationsRecord p.humidity span.data").text + op[:visibility] = noko.css("div.observationsRecord p.visibility span.data").text + op[:pressure] = noko.css("div.observationsRecord p.pressure span.data").text + + File.write(filename, op.to_json) + + sleep 600 + rescue StandardError => e + STDERR.puts "thread error!" + STDERR.puts e.message + STDERR.puts e.backtrace + end + + end + + end + @thread.run + end + + def document(url) + Nokogiri::HTML(open(url)) + end + + end + end +end diff --git a/lib/barr/manager.rb b/lib/barr/manager.rb index b96045a..e94da71 100644 --- a/lib/barr/manager.rb +++ b/lib/barr/manager.rb @@ -11,15 +11,31 @@ class Manager def initialize @count = 0 @blocks = [] + @controllers = {} end def add(block) block.manager = self @blocks << block + block.config end def destroy! @blocks.each(&:destroy!) + @controllers.values.each(&:destroy!) + end + + def controller type, opts={} + opts[:id] ||= "" + key = "#{type}_#{opts[:id]}" + + return @controllers[key] if @controllers[key] + + controller = Object.const_get("Barr::Controllers::"+type.to_s).new(opts) + @controllers[key]=controller + controller.run! + + return controller end def draw @@ -56,12 +72,25 @@ def update! begin block.update! if @count == 0 || (@count % block.interval == 0) rescue StandardError => e + STDERR.puts "block: " + e.class.name STDERR.puts e.message + STDERR.puts e.backtrace block << ERROR_ICON unless block.output.include?(ERROR_ICON) next end end + @controllers.values.each do |controller| + begin + controller.update! if @count == 1 || (@count % controller.interval == 0) + rescue StandardError => e + STDERR.puts "controller: " + e.class.name + STDERR.puts e.message + STDERR.puts e.backtrace + next + end + end + @count += 1 end diff --git a/spec/block_spec.rb b/spec/block_spec.rb index 6299d35..854cb40 100644 --- a/spec/block_spec.rb +++ b/spec/block_spec.rb @@ -85,4 +85,26 @@ expect(subject.tmp_filename).to match(/^\/tmp\/(\w|\W|block|\d)+$/i) end end + + describe "format_string_from_hash" do + before { subject.format = "${VAR1} ${VAR2} ${VAR3}" } + + it "substitutes the variables" do + opts = {var1: "test", var2: "another test", var3: "word"} + expect(subject.format_string_from_hash(opts)).to eq("test another test word") + end + + it "blanks missing variables" do + opts = {var1: "test"} + + expect(subject.format_string_from_hash(opts)).to eq("test ") + end + + it "is not case sensitive" do + opts = {var1: "test"} + subject.format = "${vAr1}" + expect(subject.format_string_from_hash(opts)).to eq("test") + end + + end end diff --git a/spec/blocks/bbc_weather_spec.rb b/spec/blocks/bbc_weather_spec.rb new file mode 100644 index 0000000..25ad7a8 --- /dev/null +++ b/spec/blocks/bbc_weather_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' +require './spec/mocks/bbc_weather' + +RSpec.describe Barr::Blocks::BBCWeatherBlockMock do + + describe '#initialize' do + it "sets default format" do + expect(subject.format).to eq("${TEMPERATURE} - ${SUMMARY}") + end + end + + describe 'config' do + it "sets the controller" do + subject.config + expect(subject.controller).to be_a(Barr::Controllers::BBCWeatherControllerMock) + end + end + + describe 'update' do + it "sets the output correctly" do + subject.location = "123456" + subject.config + subject.controller.update! + subject.update! + expect(subject.output).to eq("%{A:barr_open_url http www.bbc.co.uk/weather/123456:}17 C - Nice outside%{A}") + end + end + +end diff --git a/spec/mocks/bbc_weather.rb b/spec/mocks/bbc_weather.rb new file mode 100644 index 0000000..c5974b9 --- /dev/null +++ b/spec/mocks/bbc_weather.rb @@ -0,0 +1,39 @@ +# coding: utf-8 +require 'barr/block' +require 'barr/controller' +require 'barr/blocks/bbc_weather' +require 'barr/controllers/bbc_weather' +require 'nokogiri' + +module Barr + module Controllers + class BBCWeatherControllerMock < Barr::Controllers::BBCWeather + + def document + end + + def run! + end + + def update! + @output ||= {} + @output[:temperature] = "17 C" + @output[:summary] = "Nice outside" + @output[:windspeed] = "5 mp/h" + end + + end + end + + + module Blocks + class BBCWeatherBlockMock < Barr::Blocks::BBCWeather + def config + opts = {id: @location} + @controller = Barr::Controllers::BBCWeatherControllerMock.new opts + end + end + end +end + + From ac1fb9cfff35f55ff510f6ff40344013ed5fa5c1 Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Thu, 15 Sep 2016 11:12:42 +0100 Subject: [PATCH 02/21] release wip[ --- barr-0.2.3.gem | Bin 0 -> 17920 bytes bin/console | 0 bin/setup | 0 examples/all_in.rb | 0 examples/barr_example.rb | 0 examples/bsp.rb | 0 examples/conky.rb | 0 examples/fizzbuzz.rb | 0 examples/i3_cpu_mem.rb | 0 examples/rhythm.rb | 0 examples/time_and_date.rb | 0 examples/two_temperatures.rb | 0 spec/blocks/bbc_weather_spec.rb | 29 +++++++++++++++++++++++++++++ 13 files changed, 29 insertions(+) create mode 100644 barr-0.2.3.gem mode change 100755 => 100644 bin/console mode change 100755 => 100644 bin/setup mode change 100755 => 100644 examples/all_in.rb mode change 100755 => 100644 examples/barr_example.rb mode change 100755 => 100644 examples/bsp.rb mode change 100755 => 100644 examples/conky.rb mode change 100755 => 100644 examples/fizzbuzz.rb mode change 100755 => 100644 examples/i3_cpu_mem.rb mode change 100755 => 100644 examples/rhythm.rb mode change 100755 => 100644 examples/time_and_date.rb mode change 100755 => 100644 examples/two_temperatures.rb create mode 100644 spec/blocks/bbc_weather_spec.rb diff --git a/barr-0.2.3.gem b/barr-0.2.3.gem new file mode 100644 index 0000000000000000000000000000000000000000..2c8b56dcbaff49b228dddc2859cbb582f64e9852 GIT binary patch literal 17920 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�%tz()wvcqp@sRs>~t==PFT?2n~Q~92ZBm>?HFLU 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 S-2VNJe|zBH9{4}V1OE+Ydi3f5 literal 0 HcmV?d00001 diff --git a/bin/console b/bin/console old mode 100755 new mode 100644 diff --git a/bin/setup b/bin/setup old mode 100755 new mode 100644 diff --git a/examples/all_in.rb b/examples/all_in.rb old mode 100755 new mode 100644 diff --git a/examples/barr_example.rb b/examples/barr_example.rb old mode 100755 new mode 100644 diff --git a/examples/bsp.rb b/examples/bsp.rb old mode 100755 new mode 100644 diff --git a/examples/conky.rb b/examples/conky.rb old mode 100755 new mode 100644 diff --git a/examples/fizzbuzz.rb b/examples/fizzbuzz.rb old mode 100755 new mode 100644 diff --git a/examples/i3_cpu_mem.rb b/examples/i3_cpu_mem.rb old mode 100755 new mode 100644 diff --git a/examples/rhythm.rb b/examples/rhythm.rb old mode 100755 new mode 100644 diff --git a/examples/time_and_date.rb b/examples/time_and_date.rb old mode 100755 new mode 100644 diff --git a/examples/two_temperatures.rb b/examples/two_temperatures.rb old mode 100755 new mode 100644 diff --git a/spec/blocks/bbc_weather_spec.rb b/spec/blocks/bbc_weather_spec.rb new file mode 100644 index 0000000..25ad7a8 --- /dev/null +++ b/spec/blocks/bbc_weather_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' +require './spec/mocks/bbc_weather' + +RSpec.describe Barr::Blocks::BBCWeatherBlockMock do + + describe '#initialize' do + it "sets default format" do + expect(subject.format).to eq("${TEMPERATURE} - ${SUMMARY}") + end + end + + describe 'config' do + it "sets the controller" do + subject.config + expect(subject.controller).to be_a(Barr::Controllers::BBCWeatherControllerMock) + end + end + + describe 'update' do + it "sets the output correctly" do + subject.location = "123456" + subject.config + subject.controller.update! + subject.update! + expect(subject.output).to eq("%{A:barr_open_url http www.bbc.co.uk/weather/123456:}17 C - Nice outside%{A}") + end + end + +end From 1de1f4e12f021d39f6d3ac3c3b0cb036321949ab Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Fri, 16 Sep 2016 23:15:59 +0100 Subject: [PATCH 03/21] update version --- barr-0.2.3.gem | Bin 17920 -> 0 bytes barr-0.3.0.gem | Bin 0 -> 20480 bytes lib/barr/version.rb | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 barr-0.2.3.gem create mode 100644 barr-0.3.0.gem diff --git a/barr-0.2.3.gem b/barr-0.2.3.gem deleted file mode 100644 index 2c8b56dcbaff49b228dddc2859cbb582f64e9852..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17920 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�%tz()wvcqp@sRs>~t==PFT?2n~Q~92ZBm>?HFLU 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 S-2VNJe|zBH9{4}V1OE+Ydi3f5 diff --git a/barr-0.3.0.gem b/barr-0.3.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..19d1b0c12de908eaef7d484f22133780e58618ef GIT binary patch literal 20480 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 MGz3ONV6cP$03up2GXMYp literal 0 HcmV?d00001 diff --git a/lib/barr/version.rb b/lib/barr/version.rb index b4059a8..fbec57e 100644 --- a/lib/barr/version.rb +++ b/lib/barr/version.rb @@ -1,3 +1,3 @@ module Barr - VERSION = "0.2.3" + VERSION = "0.3.0" end From e265e232b3e33e05b3bc390a492214a289dcda3d Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Thu, 27 Oct 2016 02:49:39 +0100 Subject: [PATCH 04/21] Fix bspwm issues --- .gitignore | 1 + barr-0.3.0.gem | Bin 20480 -> 0 bytes lib/barr/blocks/bspwm.rb | 15 +- spec/blocks/bspwm_spec.rb | 12 +- spec/mocks/bspwm.rb | 2606 ++++++++++++++----------------------- 5 files changed, 993 insertions(+), 1641 deletions(-) delete mode 100644 barr-0.3.0.gem diff --git a/.gitignore b/.gitignore index 381affa..566793e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ [#]*[#] .\#* .swp +barr-*.gem diff --git a/barr-0.3.0.gem b/barr-0.3.0.gem deleted file mode 100644 index 19d1b0c12de908eaef7d484f22133780e58618ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 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 MGz3ONV6cP$03up2GXMYp diff --git a/lib/barr/blocks/bspwm.rb b/lib/barr/blocks/bspwm.rb index 8024363..5228ed1 100644 --- a/lib/barr/blocks/bspwm.rb +++ b/lib/barr/blocks/bspwm.rb @@ -19,18 +19,17 @@ def update! @tree = nil op = [] focused = "" - bsp_tree["monitors"].each do |monitor| - next if monitor["name"] != @monitor - focused = monitor["focusedDesktopName"] + next if (monitor["id"] != @monitor) && (monitor["name"] != @monitor) + focused = monitor["focusedDesktopId"] monitor["desktops"].each do |desktop| - if desktop["name"] == focused + if desktop["id"] == focused op << focused_desktop(desktop) else op << unfocused_desktop(desktop) end end - + end @output = op.join(" ") @@ -53,15 +52,15 @@ def focused_desktop desktop def unfocused_desktop desktop op = "" - op += "%{A:bspc desktop -f #{desktop["name"].gsub(":","\:")}:} " + op += "%{A:bspc desktop -f #{desktop["id"]}:} " op += "#{desktop["name"]}" op += " %{A}" return op end - + def first_monitor - bsp_tree["primaryMonitorName"] + bsp_tree["monitors"].first["id"] end def sys_cmd diff --git a/spec/blocks/bspwm_spec.rb b/spec/blocks/bspwm_spec.rb index 54600a5..04b2b86 100644 --- a/spec/blocks/bspwm_spec.rb +++ b/spec/blocks/bspwm_spec.rb @@ -17,7 +17,7 @@ end it "sets default monitor" do - expect(subject.monitor).to eq("DP-4") + expect(subject.monitor).to eq(2097153) end end @@ -30,8 +30,8 @@ end it "desktops" do - expect(subject.tree["monitors"].first["desktops"].count).to eq(10) - expect(subject.tree["monitors"].first["desktops"].first["name"]).to eq("I") + expect(subject.tree["monitors"].first["desktops"].count).to eq(6) + expect(subject.tree["monitors"].first["desktops"].first["name"]).to eq("web") end end @@ -40,7 +40,7 @@ before { subject.update! } it "renders output correctly" do - expect(subject.output).to eq("> I < %{A:bspc desktop -f II:} II %{A} %{A:bspc desktop -f III:} III %{A} %{A:bspc desktop -f IV:} IV %{A} %{A:bspc desktop -f V:} V %{A} %{A:bspc desktop -f VI:} VI %{A} %{A:bspc desktop -f VII:} VII %{A} %{A:bspc desktop -f VIII:} VIII %{A} %{A:bspc desktop -f IX:} IX %{A} %{A:bspc desktop -f X:} X %{A}") + expect(subject.output).to eq("> web < %{A:bspc desktop -f 2097156:} media %{A} %{A:bspc desktop -f 2097157:} web %{A} %{A:bspc desktop -f 2097158:} shell %{A} %{A:bspc desktop -f 2097159:} steam %{A} %{A:bspc desktop -f 2097160:} sys %{A}") end end @@ -59,7 +59,7 @@ before { @op = subject.focused_desktop(@fd) } it "renders in the correct format" do - expect(@op).to eq("%{R}> I <%{R}") + expect(@op).to eq("%{R}> web <%{R}") end end @@ -67,7 +67,7 @@ before { @op = subject.unfocused_desktop(@ud) } it "renders in the correct format" do - expect(@op).to eq("%{A:bspc desktop -f X:} X %{A}") + expect(@op).to eq("%{A:bspc desktop -f 2097160:} sys %{A}") end end end diff --git a/spec/mocks/bspwm.rb b/spec/mocks/bspwm.rb index 4e1ec37..df538b6 100644 --- a/spec/mocks/bspwm.rb +++ b/spec/mocks/bspwm.rb @@ -1,1630 +1,982 @@ - $bsp_json = < Date: Sat, 29 Oct 2016 01:51:27 +0100 Subject: [PATCH 05/21] Added format options to CPU block --- README.md | 9 ++++++++- examples/all_in.rb | 2 +- examples/i3_cpu_mem.rb | 2 +- lib/barr/blocks/cpu.rb | 22 +++++++++++++++++----- spec/blocks/cpu_spec.rb | 18 ++++++++++++++---- 5 files changed, 41 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 18ffa07..7c2e3cc 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,14 @@ Shows CPU load averaged across all cores. `cpu = Barr::Blocks::CPU.new` -There are no `CPU` block specific configurable options. +| Option | Value | Description | Default | +| --- | --- | --- | --- | +| `format` | string | Configurable format for showing which weather information is displayed. See table below for options. | `"${LOAD}"` | + +| Option | Description | +| --- | --- | +| `${LOAD}` | Current load in % | +| `${TEMP}` | Current temperature | #### HDD diff --git a/examples/all_in.rb b/examples/all_in.rb index 702460f..f5a2492 100644 --- a/examples/all_in.rb +++ b/examples/all_in.rb @@ -39,7 +39,7 @@ icon: "\uf0c2 Philadelphia: ", interval: 1500) -cpu = Barr::Blocks::CPU.new icon: "\uf1fe" +cpu = Barr::Blocks::CPU.new icon: "\uf1fe", format: "${LOAD}% ${TEMP}" mem = Barr::Blocks::Mem.new bgcolor: '#333333' diff --git a/examples/i3_cpu_mem.rb b/examples/i3_cpu_mem.rb index 50ab18b..14997d6 100644 --- a/examples/i3_cpu_mem.rb +++ b/examples/i3_cpu_mem.rb @@ -7,7 +7,7 @@ i3 = Barr::Blocks::I3.new icon: "\uf108", bgcolor: '#114152', fgcolor: '#DAC1DE', align: :l, focus_markers: ["| \uf0a4",' |'], invert_focus_colors: true, interval: 0.2 -cpu = Barr::Blocks::CPU.new icon: "\uf108 CPU:", bgcolor: '#491A5E', align: :r +cpu = Barr::Blocks::CPU.new icon: "\uf108 CPU:", bgcolor: '#491A5E', align: :r, format: "${LOAD}" mem = Barr::Blocks::Mem.new icon: 'RAM:', align: :r, bgcolor: '#2F113D' diff --git a/lib/barr/blocks/cpu.rb b/lib/barr/blocks/cpu.rb index 5c5a54a..fb847eb 100644 --- a/lib/barr/blocks/cpu.rb +++ b/lib/barr/blocks/cpu.rb @@ -1,19 +1,31 @@ +# coding: utf-8 require 'barr/block' module Barr module Blocks class CPU < Block + def initialize opts={} + super + @format = opts[:format] || "${LOAD}" + end + def update! - idle = sys_cmd.scan(/(\d{1,3}\.\d) id/).flatten.first.to_f + op = {} + op[:load] = load_sys_cmd.to_f.round(2).to_s + "%" + op[:temp] = (temp_sys_cmd.to_f.round(2) / 1000).to_s + "°" - @output = "#{(100 - idle).round(1)}%" + @output = format_string_from_hash(op) end - + private - def sys_cmd - `top -bn1 | grep 'Cpu(s)'`.chomp + def load_sys_cmd + `grep 'cpu ' /proc/stat | awk -v RS="" '{print ($13-$2+$15-$4)*100/($13-$2+$15-$4+$16-$5)}'` + end + + def temp_sys_cmd + `cat /sys/class/thermal/thermal_zone0/temp` end end diff --git a/spec/blocks/cpu_spec.rb b/spec/blocks/cpu_spec.rb index 92111d0..0c66d26 100644 --- a/spec/blocks/cpu_spec.rb +++ b/spec/blocks/cpu_spec.rb @@ -1,17 +1,27 @@ +# coding: utf-8 require 'barr/blocks/cpu' RSpec.describe Barr::Blocks::CPU do describe '#update!' do - let(:sys_cmd) { '%Cpu(s): 7.9 us, 1.2 sy, 1.7 ni, 88.6 id, 0.5 wa' } + let(:load_sys_cmd) { '6.7744' } + let(:temp_sys_cmd) { '28500' } before do - allow(subject).to receive(:sys_cmd).and_return(sys_cmd) + allow(subject).to receive(:load_sys_cmd).and_return(load_sys_cmd) + allow(subject).to receive(:temp_sys_cmd).and_return(temp_sys_cmd) + end + + it 'sets the load data correctly' do + subject.format = '${LOAD}' subject.update! + expect(subject.output).to eq '6.77%' end - it 'sets the data correctly' do - expect(subject.output).to eq '11.4%' + it 'sets the temp data correctly' do + subject.format = '${TEMP}' + subject.update! + expect(subject.output).to eq '28.5°' end end From cd7c461d955f2579f4e8cb565be9865a18912193 Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Sat, 29 Oct 2016 02:03:09 +0100 Subject: [PATCH 06/21] Remove redundant method and fix typos --- README.md | 4 ++-- lib/barr/block.rb | 19 ------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index c0ce0b9..efec97c 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ Show battery status. Shows configurable weather information as provided by the BBC. Recommended over the `Temperature` block due to how much more reliable the BBC service is. -`bbc = Barr::Blocks::BBCWeather.new location: "5308655", format: "${TEMPERATURE} wind: ${WINDSPEED} ${WINDDIRECTION}" +`bbc = Barr::Blocks::BBCWeather.new location: "5308655", format: "${TEMPERATURE} wind: ${WINDSPEED} ${WINDDIRECTION}"` | Option | Value | Description | Default | | --- | --- | --- | --- | @@ -180,7 +180,7 @@ Shows configurable weather information as provided by the BBC. Recommended over | `${WINDSPEED}` | Current wind speed | | `${WINDDIRECTION}` | Current wind direction | | `${HUMIDITY}` | Current humidity percentage | -| `${VISIBILITY}` | Sumamry of visbility, e.g. "Excellent" | +| `${VISIBILITY}` | Summary of visbility, e.g. "Excellent" | | `${PRESSURE}` | Current pressure and trend, e.g. "1000mb, Falling" | #### Bspwm (Experimental) diff --git a/lib/barr/block.rb b/lib/barr/block.rb index b4b4539..aef40f0 100644 --- a/lib/barr/block.rb +++ b/lib/barr/block.rb @@ -42,25 +42,6 @@ def tmp_filename return @tmp_filename end - def substitue_variables string_format, subs - reg = /\$\{\w+\}/i - new_string = string_format - matches = string_format.scan reg - matches.each do |match| - keyword = match.scan(/\w+/i).first.downcase - - if subs.has_key? keyword - sub = keyword - else - sub = "" - end - - new_string.gsub!(match, sub) - end - - return new_string - end - def format_string_from_hash(hash) formatted = @format.clone matches = @format.scan(/([\$][\{](\w+)[\}])/) From 7d9ae1c41c4490756c85575677f368699f719790 Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Sun, 6 Nov 2016 07:10:08 +0000 Subject: [PATCH 07/21] Added HTTPGrab block --- README.md | 13 ++++++++ barr.gemspec | 3 +- examples/http_grab.rb | 16 ++++++++++ lib/barr.rb | 2 ++ lib/barr/blocks/http_grab.rb | 25 +++++++++++++++ lib/barr/controller.rb | 2 +- lib/barr/controllers/bbc_weather.rb | 4 --- lib/barr/controllers/http_grab.rb | 48 +++++++++++++++++++++++++++++ spec/blocks/http_grab_spec.rb | 31 +++++++++++++++++++ spec/mocks/http_grab.rb | 38 +++++++++++++++++++++++ 10 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 examples/http_grab.rb create mode 100644 lib/barr/blocks/http_grab.rb create mode 100644 lib/barr/controllers/http_grab.rb create mode 100644 spec/blocks/http_grab_spec.rb create mode 100644 spec/mocks/http_grab.rb diff --git a/README.md b/README.md index efec97c..70bd4fa 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,19 @@ Shows selected filesystem's used and free space. | --- | --- | --- | --- | | `device` | String | This is the name of the device for which you'd like to see free/used space. Something like `/dev/sda2`. Run `df -h` in your terminal and look at the first column. | **REQUIRED** | +#### HTTPGrab + +Grabs a piece of text from a URL based on a css or xpath selector. Optionally opens the link in a browser when clicked. Makes a reasonable effort at supporting pages controlled by javascript. + +`http = Barr::Blocks::HTTPGrab.new url: "http://www.bbc.co.uk/news", selector: "span.most-popular-list-item__headline"` + +| Option | Value | Description | Default | +| --- | --- | --- | --- | +| `link` | Bool | Set to `true` or `false` to set whether or not the block should open the given URL in a browser when clicked. | `false` | +| `selector` | String | The CSS or XPath selector for the DOM node of the text you'd like grabbed | **REQUIRED** | +| `type` | Symbol | Set to `:css` or `:xpath` to set which type of selector you have provided | `:css` | +| `url` | String | URL that you'd like to grab from | **REQUIRED** | + #### I3 **Requires i3wm**. Shows the current workspaces and highlights the active one. You can click a workspace name to change to there. diff --git a/barr.gemspec b/barr.gemspec index e48a42a..a360215 100644 --- a/barr.gemspec +++ b/barr.gemspec @@ -29,11 +29,12 @@ Gem::Specification.new do |spec| spec.add_development_dependency "rake", "~> 10.0" spec.add_development_dependency "rspec", "~> 3.0" spec.add_development_dependency "timecop", "~> 0.8.0" - spec.add_development_dependency "pry", "~> 0.10" + spec.add_development_dependency "pry-byebug", "~> 3.4" spec.add_runtime_dependency "i3ipc", "0.2.0" spec.add_runtime_dependency "weather-api", "1.2.0" spec.add_runtime_dependency "nokogiri", "~> 1.6" + spec.add_runtime_dependency "poltergeist", "~> 1.11" spec.requirements << "Lemonbar with XFT support (https://github.com/krypt-n/bar)" spec.requirements << "(Optional) I3 for Workspace support" diff --git a/examples/http_grab.rb b/examples/http_grab.rb new file mode 100644 index 0000000..b988728 --- /dev/null +++ b/examples/http_grab.rb @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby + +require 'rubygems' +require 'barr' + +@man = Barr::Manager.new + +grab = Barr::Blocks::HTTPGrab.new url: "http://www.bbc.co.uk/news", + icon: "Top News:", + type: :css, + selector: "span.most-popular-list-item__headline", + link: true + +@man.add grab + +@man.run! diff --git a/lib/barr.rb b/lib/barr.rb index 4ffc46f..fb8c18e 100644 --- a/lib/barr.rb +++ b/lib/barr.rb @@ -10,6 +10,7 @@ require 'barr/blocks/conky' require 'barr/blocks/cpu' require 'barr/blocks/hdd' +require 'barr/blocks/http_grab' require 'barr/blocks/i3' require 'barr/blocks/ip' require 'barr/blocks/mem' @@ -21,6 +22,7 @@ require 'barr/blocks/separator' require 'barr/controllers/bbc_weather' +require 'barr/controllers/http_grab' module Barr end diff --git a/lib/barr/blocks/http_grab.rb b/lib/barr/blocks/http_grab.rb new file mode 100644 index 0000000..ca72dbd --- /dev/null +++ b/lib/barr/blocks/http_grab.rb @@ -0,0 +1,25 @@ +module Barr + module Blocks + class HTTPGrab < Block + attr_accessor :url, :type, :selector, :link + + def initialize opts={} + super + @url = opts[:url] + @type = opts[:type] || :css + @selector = opts[:selector] + @link = !!opts[:link] + end + + def config + opts = {url: @url, type: @type, selector: @selector} + @controller = @manager.controller :HTTPGrab, opts + end + + def update! + @output = @controller.output[:text] + @output = "%{A:barr_open_url #{@url.gsub("://"," ").gsub("/","\/")}:}#{@output}%{A}" if @link + end + end + end +end diff --git a/lib/barr/controller.rb b/lib/barr/controller.rb index d96aed5..166d362 100644 --- a/lib/barr/controller.rb +++ b/lib/barr/controller.rb @@ -13,7 +13,7 @@ def run! end def update! - + @output = JSON.parse(`cat #{filename}`, symbolize_names: true) end def file diff --git a/lib/barr/controllers/bbc_weather.rb b/lib/barr/controllers/bbc_weather.rb index bb78f68..dbf39b5 100644 --- a/lib/barr/controllers/bbc_weather.rb +++ b/lib/barr/controllers/bbc_weather.rb @@ -13,10 +13,6 @@ def initialize opts={} @speed_unit = (opts[:speed_unit] || "mph").downcase end - def update! - @output = JSON.parse(`cat #{filename}`, symbolize_names: true) - end - def run! @thread = Thread.new do loop do diff --git a/lib/barr/controllers/http_grab.rb b/lib/barr/controllers/http_grab.rb new file mode 100644 index 0000000..3b1d554 --- /dev/null +++ b/lib/barr/controllers/http_grab.rb @@ -0,0 +1,48 @@ +require 'capybara' +require 'capybara/dsl' +require 'capybara/poltergeist' + +Capybara.default_driver = :poltergeist +Capybara.run_server = false + +module Barr + module Controllers + class HTTPGrab < Controller + include Capybara::DSL + + def initialize opts={} + super + @type = (opts[:type] || 'css').downcase.to_sym + @selector = opts[:selector] + @url = opts[:url] + end + + def run! + @thread = Thread.new do + loop do + begin + grabbed = "" + visit(@url) + noko = Nokogiri::HTML(page.html) + + if @type == :css + grabbed = noko.css(@selector).first.text + elsif @type == :xpath + grabbed = noko.xpath(@selector).first.text + end + + File.write(filename, {text: grabbed}.to_json) + + sleep @interval + rescue StandardError => e + STDERR.puts "HTTPGrab Controller Error" + STDERR.puts e.message + STDERR.puts e.backtrace + end + end + end + @thread.run + end + end + end +end diff --git a/spec/blocks/http_grab_spec.rb b/spec/blocks/http_grab_spec.rb new file mode 100644 index 0000000..5e17663 --- /dev/null +++ b/spec/blocks/http_grab_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' +require './spec/mocks/http_grab' + +RSpec.describe Barr::Blocks::HTTPGrabBlockMock do + + describe '#initialize' do + it "sets defaults" do + expect(subject.link).to be_falsey + expect(subject.type).to eq(:css) + end + end + + describe 'config' do + it "sets the controller" do + subject.config + expect(subject.controller).to be_a(Barr::Controllers::HTTPGrabControllerMock) + end + end + + describe 'update' do + it "sets the output correctly" do + subject.url = "http://fakedomain.com/url" + subject.link = true + subject.config + subject.controller.update! + subject.update! + expect(subject.output).to eq("%{A:barr_open_url http fakedomain.com/url:}Top news article!%{A}") + end + end + +end diff --git a/spec/mocks/http_grab.rb b/spec/mocks/http_grab.rb new file mode 100644 index 0000000..826833a --- /dev/null +++ b/spec/mocks/http_grab.rb @@ -0,0 +1,38 @@ +# coding: utf-8 +require 'barr/block' +require 'barr/controller' +require 'barr/blocks/http_grab' +require 'barr/controllers/http_grab' +require 'nokogiri' + +module Barr + module Controllers + class HTTPGrabControllerMock < Barr::Controllers::HTTPGrab + + def document + end + + def run! + end + + def update! + @output ||= {} + @output[:text] = "Top news article!" + end + + end + end + + + module Blocks + class HTTPGrabBlockMock < Barr::Blocks::HTTPGrab + def config + opts = {id: "http://fakedomain.com/url", type: :css, selector: "span.mocked_class", link: true} + + @controller = Barr::Controllers::HTTPGrabControllerMock.new opts + end + end + end +end + + From e20ce96ef2b0416e113955f227418eae5d4a7128 Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Tue, 8 Nov 2016 04:18:05 +0000 Subject: [PATCH 08/21] Added HueLight Block --- README.md | 9 ++++ barr.gemspec | 1 + examples/hue.rb | 14 ++++++ lib/barr.rb | 1 + lib/barr/block.rb | 16 +++++-- lib/barr/blocks/hue_light.rb | 81 +++++++++++++++++++++++++++++++++++ spec/blocks/hue_light_spec.rb | 63 +++++++++++++++++++++++++++ 7 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 examples/hue.rb create mode 100644 lib/barr/blocks/hue_light.rb create mode 100644 spec/blocks/hue_light_spec.rb diff --git a/README.md b/README.md index 70bd4fa..c5bba6d 100644 --- a/README.md +++ b/README.md @@ -254,6 +254,15 @@ Grabs a piece of text from a URL based on a css or xpath selector. Optionally op | `type` | Symbol | Set to `:css` or `:xpath` to set which type of selector you have provided | `:css` | | `url` | String | URL that you'd like to grab from | **REQUIRED** | +#### HueLight + +**Requires [Hue](https://github.com/soffes/hue) gem to be installed and configured prior to use** Allows you to set buttons for controlling a single Philips Hue Light. + +| Option | Value | Description | Default | +| --- | --- | --- | --- | +| `id` | `hue` light ID | You can list all of your lights and their IDs by running `hue lights`. The ID is the first column, e.g. `1`. | **REQUIRED** | +| `format` | string | Configurable format for + #### I3 **Requires i3wm**. Shows the current workspaces and highlights the active one. You can click a workspace name to change to there. diff --git a/barr.gemspec b/barr.gemspec index a360215..2cdb0dd 100644 --- a/barr.gemspec +++ b/barr.gemspec @@ -35,6 +35,7 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency "weather-api", "1.2.0" spec.add_runtime_dependency "nokogiri", "~> 1.6" spec.add_runtime_dependency "poltergeist", "~> 1.11" + spec.add_runtime_dependency "hue", "~> 0.2" spec.requirements << "Lemonbar with XFT support (https://github.com/krypt-n/bar)" spec.requirements << "(Optional) I3 for Workspace support" diff --git a/examples/hue.rb b/examples/hue.rb new file mode 100644 index 0000000..6ef032d --- /dev/null +++ b/examples/hue.rb @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby + +require 'rubygems' +require 'barr' + +@man = Barr::Manager.new + +light = Barr::Blocks::HueLight.new id: "5", + icon: "\uf0eb", + format: "${OFF:T-Turn Off} ${ON} ${ON:B-50,T-Dim 25%} ${ON:A-lselect,T-Alert!}" + +@man.add light + +@man.run! diff --git a/lib/barr.rb b/lib/barr.rb index fb8c18e..4c7156f 100644 --- a/lib/barr.rb +++ b/lib/barr.rb @@ -11,6 +11,7 @@ require 'barr/blocks/cpu' require 'barr/blocks/hdd' require 'barr/blocks/http_grab' +require 'barr/blocks/hue_light' require 'barr/blocks/i3' require 'barr/blocks/ip' require 'barr/blocks/mem' diff --git a/lib/barr/block.rb b/lib/barr/block.rb index aef40f0..8cdc5ce 100644 --- a/lib/barr/block.rb +++ b/lib/barr/block.rb @@ -42,14 +42,22 @@ def tmp_filename return @tmp_filename end - def format_string_from_hash(hash) - formatted = @format.clone - matches = @format.scan(/([\$][\{](\w+)[\}])/) + def wrap_button text, action + "%{A:#{action}:}#{text}%{A}" + end + def format_string_from_hash(hash, sender=nil) + formatted = @format.clone + matches = @format.scan(/([\$][\{](\w+)(:?([^:\}]+)?)[\}])/) + # binding.pry matches.each do |match| key = match[1].downcase.to_sym if hash.has_key? key - sub = hash[key] + if !match[3].nil? && sender && sender.respond_to?(:additions_for_format) + sub = sender.additions_for_format(key, match[3]) + else + sub = hash[key] + end else sub = "" end diff --git a/lib/barr/blocks/hue_light.rb b/lib/barr/blocks/hue_light.rb new file mode 100644 index 0000000..0ba4af1 --- /dev/null +++ b/lib/barr/blocks/hue_light.rb @@ -0,0 +1,81 @@ +require 'barr/block' + +module Barr + module Blocks + class HueLight < Block + attr_accessor :id + + def initialize(opts = {}) + super + + @id = opts[:id] + @format = opts[:format] || "${ON} ${OFF}" + end + + def update! + @output = format_string_from_hash(base_options, self) + end + + def additions_for_format(key, option_str) + agg = [] + text = "" + options = option_str.split(/(? Date: Tue, 8 Nov 2016 04:18:05 +0000 Subject: [PATCH 09/21] Added HueLight Block --- README.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c5bba6d..de8a15e 100644 --- a/README.md +++ b/README.md @@ -261,7 +261,29 @@ Grabs a piece of text from a URL based on a css or xpath selector. Optionally op | Option | Value | Description | Default | | --- | --- | --- | --- | | `id` | `hue` light ID | You can list all of your lights and their IDs by running `hue lights`. The ID is the first column, e.g. `1`. | **REQUIRED** | -| `format` | string | Configurable format for +| `format` | string | Configurable format for choosing the buttons and their behaviours. See table below for options | `"${OFF} ${ON}"`| + +| Option | Description | +| `${OFF}` | Adds a button to turn the selected light off. Can be configured with custom text | +| `${ON}` | Adss a button to turn the selected light on. Several buttons can be added with individual behaviours | + +Both the `${OFF}` and `${ON}` buttons allow additional button specific behaviours to be configured. The supported options are: + +| Option | Description | +| `B` | Brightness. Value between `0` and `255`. +| `H` | Hue. Value between `0` and `65535`. +| `A` | Alert. Value of either `select` (for a single flash) or `lselect` (for 30s of flashing) +| `T` | Button Text. Any character string that will be shown as the button's text. + +These can be applied to the Block's `format` string options by appending them with a colon and passing the option with a hyphen: + +`${ON:B-25}` - Sets the light's brightness to 25 (out of 255). + +You can add multiple options to a single button by separating the options with a comma: + +`${ON:B-255,T-Bright}` - creates a button that looks like `[Bright]` which sets the light to maximum brightness. + +See the [hue.rb](https://github.com/OkayDave/barr/blob/develop/examples/hue.rb) file for more examples. #### I3 From c7d04bd70576fc30ffcee2d65fc1f0184d88cde0 Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Fri, 11 Nov 2016 07:13:00 +0000 Subject: [PATCH 10/21] Added HueGroup block --- README.md | 35 +++++++++++++++++++ examples/all_in.rb | 7 ++++ examples/hue.rb | 10 ++++-- lib/barr.rb | 1 + lib/barr/blocks/hue_group.rb | 16 +++++++++ spec/blocks/hue_group_spec.rb | 63 +++++++++++++++++++++++++++++++++++ 6 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 lib/barr/blocks/hue_group.rb create mode 100644 spec/blocks/hue_group_spec.rb diff --git a/README.md b/README.md index de8a15e..409ecb4 100644 --- a/README.md +++ b/README.md @@ -254,10 +254,45 @@ Grabs a piece of text from a URL based on a css or xpath selector. Optionally op | `type` | Symbol | Set to `:css` or `:xpath` to set which type of selector you have provided | `:css` | | `url` | String | URL that you'd like to grab from | **REQUIRED** | +#### HueGroup + +**Requires [Hue](https://github.com/soffes/hue) gem to be installed and configured prior to use** Allows you to set buttons for controlling a designated Philips Hue Light group. This sends all options to all lights on the group. + +`group = Barr::Blocks::HueGroup.new id: '3', format: "${ON:T-Turn On} ${ON:B-100,T-Dim}", ${OFF}'` + +| Option | Value | Description | Default | +| --- | --- | --- | --- | +| `id` | `hue` group ID | You can list all of your lights and their IDs by running `hue groups`. The ID is the first column, e.g. `1`. | **REQUIRED** | +| `format` | string | Configurable format for choosing the buttons and their behaviours. See table below for options | `"${OFF} ${ON}"`| + +| Option | Description | +| `${OFF}` | Adds a button to turn the selected light off. Can be configured with custom text | +| `${ON}` | Adss a button to turn the selected light on. Several buttons can be added with individual behaviours | + +Both the `${OFF}` and `${ON}` buttons allow additional button specific behaviours to be configured. The supported options are: + +| Option | Description | +| `B` | Brightness. Value between `0` and `255`. +| `H` | Hue. Value between `0` and `65535`. +| `A` | Alert. Value of either `select` (for a single flash) or `lselect` (for 30s of flashing) +| `T` | Button Text. Any character string that will be shown as the button's text. + +These can be applied to the Block's `format` string options by appending them with a colon and passing the option with a hyphen: + +`${ON:B-25}` - Sets the light's brightness to 25 (out of 255). + +You can add multiple options to a single button by separating the options with a comma: + +`${ON:B-255,T-Bright}` - creates a button that looks like `[Bright]` which sets the light to maximum brightness. + +See the [hue.rb](https://github.com/OkayDave/barr/blob/develop/examples/hue.rb) file for more examples. + #### HueLight **Requires [Hue](https://github.com/soffes/hue) gem to be installed and configured prior to use** Allows you to set buttons for controlling a single Philips Hue Light. +`light = Barr::Blocks::HueLight.new id: '3', format: "${ON:T-Turn On} ${ON:B-100,T-Dim}", ${OFF}'` + | Option | Value | Description | Default | | --- | --- | --- | --- | | `id` | `hue` light ID | You can list all of your lights and their IDs by running `hue lights`. The ID is the first column, e.g. `1`. | **REQUIRED** | diff --git a/examples/all_in.rb b/examples/all_in.rb index f5a2492..3a448a3 100644 --- a/examples/all_in.rb +++ b/examples/all_in.rb @@ -47,6 +47,12 @@ local = Barr::Blocks::IP.new bgcolor: '#937739', align: :r, icon: "\uf1ce" +office_lights = Barr::Blocks::HueGroup.new id: "3", + icon: "\uf1ad", + format: "${OFF} ${ON:H-1,H-65535,B-255} ${ON:B-120,T-dim}", + align: :r, + bgcolor: '#0c1e3a', + fcolor: '#EEEEEE' # Left @man.add artist @man.add song @@ -56,6 +62,7 @@ @man.add hdd # Right +@man.add office_lights @man.add i3 @man.add local @man.add who diff --git a/examples/hue.rb b/examples/hue.rb index 6ef032d..a8ef311 100644 --- a/examples/hue.rb +++ b/examples/hue.rb @@ -5,10 +5,16 @@ @man = Barr::Manager.new -light = Barr::Blocks::HueLight.new id: "5", +light = Barr::Blocks::HueLight.new id: "6", icon: "\uf0eb", - format: "${OFF:T-Turn Off} ${ON} ${ON:B-50,T-Dim 25%} ${ON:A-lselect,T-Alert!}" + format: "${OFF:T-Turn Off} ${ON} ${ON:B-50,T-Dim 25%,H-34332} ${ON:A-lselect,T-Alert!,H-65535}" + +group = Barr::Blocks::HueGroup.new id: "3", + icon: "\uf1ad", + format: "${OFF:T-Turn Off} ${ON:H-1,T-Turn On}" + @man.add light +@man.add group @man.run! diff --git a/lib/barr.rb b/lib/barr.rb index 4c7156f..e435300 100644 --- a/lib/barr.rb +++ b/lib/barr.rb @@ -12,6 +12,7 @@ require 'barr/blocks/hdd' require 'barr/blocks/http_grab' require 'barr/blocks/hue_light' +require 'barr/blocks/hue_group' require 'barr/blocks/i3' require 'barr/blocks/ip' require 'barr/blocks/mem' diff --git a/lib/barr/blocks/hue_group.rb b/lib/barr/blocks/hue_group.rb new file mode 100644 index 0000000..40d85db --- /dev/null +++ b/lib/barr/blocks/hue_group.rb @@ -0,0 +1,16 @@ +require 'barr/block' + +module Barr + module Blocks + class HueGroup < Barr::Blocks::HueLight + attr_accessor :id + + private + + def sys_cmd + "hue group #{@id}" + end + + end + end +end diff --git a/spec/blocks/hue_group_spec.rb b/spec/blocks/hue_group_spec.rb new file mode 100644 index 0000000..e6a14b2 --- /dev/null +++ b/spec/blocks/hue_group_spec.rb @@ -0,0 +1,63 @@ +# coding: utf-8 +require 'barr/blocks/hue_group' + +RSpec.describe Barr::Blocks::HueGroup do + + describe '#update!' do + before do + subject.id = 5 + end + + describe "the output" do + it 'sets the default off button correctly' do + subject.format = '${OFF}' + subject.update! + expect(subject.output).to eq '%{A:hue group 5 off:}[off]%{A}' + end + + it 'sets the default on button correctly' do + subject.format = '${ON}' + subject.update! + expect(subject.output).to eq '%{A:hue group 5 on:}[on]%{A}' + end + + it "sets custom text correctly" do + subject.format = '${OFF:T-custom off}' + subject.update! + expect(subject.output).to eq '%{A:hue group 5 off:}[custom off]%{A}' + end + + it "sets hue correctly" do + subject.format = '${ON:H-1500}' + subject.update! + expect(subject.output).to eq '%{A:hue group 5 --hue 1500:}[on]%{A}' + end + + it "sets alerts correctly" do + subject.format = '${ON:A-lselect}' + subject.update! + expect(subject.output).to eq '%{A:hue group 5 --alert lselect:}[on]%{A}' + end + + it "sets brightness correctly" do + subject.format = '${ON:B-25}' + subject.update! + expect(subject.output).to eq '%{A:hue group 5 --brightness 25:}[on]%{A}' + end + + it "sets multiple options correctly" do + subject.format = "${ON:B-200,T-Quite Bright,H-65000}" + subject.update! + expect(subject.output).to eq '%{A:hue group 5 --brightness 200 --hue 65000:}[Quite Bright]%{A}' + end + + it "sets multiple buttons correctly" do + subject.format = "${OFF:T-turn off} ${ON}" + subject.update! + expect(subject.output).to eq("%{A:hue group 5 off:}[turn off]%{A} %{A:hue group 5 on:}[on]%{A}") + end + + end + end + +end From 601d4280f16a8b754869cb256e5c1c93f7355413 Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Wed, 26 Jul 2017 07:17:11 +0100 Subject: [PATCH 11/21] Added playerctl block --- README.md | 40 ++++++++++++++++++++------- barr.gemspec | 1 + lib/barr.rb | 2 ++ lib/barr/blocks/playerctl.rb | 43 +++++++++++++++++++++++++++++ lib/barr/controllers/playerctl.rb | 46 +++++++++++++++++++++++++++++++ spec/blocks/playerctl_spec.rb | 29 +++++++++++++++++++ spec/mocks/playerctl.rb | 36 ++++++++++++++++++++++++ 7 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 lib/barr/blocks/playerctl.rb create mode 100644 lib/barr/controllers/playerctl.rb create mode 100644 spec/blocks/playerctl_spec.rb create mode 100644 spec/mocks/playerctl.rb diff --git a/README.md b/README.md index 409ecb4..0175958 100644 --- a/README.md +++ b/README.md @@ -272,10 +272,10 @@ Grabs a piece of text from a URL based on a css or xpath selector. Optionally op Both the `${OFF}` and `${ON}` buttons allow additional button specific behaviours to be configured. The supported options are: | Option | Description | -| `B` | Brightness. Value between `0` and `255`. -| `H` | Hue. Value between `0` and `65535`. -| `A` | Alert. Value of either `select` (for a single flash) or `lselect` (for 30s of flashing) -| `T` | Button Text. Any character string that will be shown as the button's text. +| `B` | Brightness. Value between `0` and `255`. | +| `H` | Hue. Value between `0` and `65535`. | +| `A` | Alert. Value of either `select` (for a single flash) or `lselect` (for 30s of flashing) | +| `T` | Button Text. Any character string that will be shown as the button's text. | These can be applied to the Block's `format` string options by appending them with a colon and passing the option with a hyphen: @@ -299,16 +299,18 @@ See the [hue.rb](https://github.com/OkayDave/barr/blob/develop/examples/hue.rb) | `format` | string | Configurable format for choosing the buttons and their behaviours. See table below for options | `"${OFF} ${ON}"`| | Option | Description | +| --- | --- | | `${OFF}` | Adds a button to turn the selected light off. Can be configured with custom text | -| `${ON}` | Adss a button to turn the selected light on. Several buttons can be added with individual behaviours | +| `${ON}` | Adds a button to turn the selected light on. Several buttons can be added with individual behaviours | Both the `${OFF}` and `${ON}` buttons allow additional button specific behaviours to be configured. The supported options are: | Option | Description | -| `B` | Brightness. Value between `0` and `255`. -| `H` | Hue. Value between `0` and `65535`. -| `A` | Alert. Value of either `select` (for a single flash) or `lselect` (for 30s of flashing) -| `T` | Button Text. Any character string that will be shown as the button's text. +| --- | --- | +| `B` | Brightness. Value between `0` and `255`. | +| `H` | Hue. Value between `0` and `65535`. | +| `A` | Alert. Value of either `select` (for a single flash) or `lselect` (for 30s of flashing) | +| `T` | Button Text. Any character string that will be shown as the button's text. | These can be applied to the Block's `format` string options by appending them with a colon and passing the option with a hyphen: @@ -350,6 +352,24 @@ Shows current RAM usage. There are no `Mem` block specific configurable options. +#### Playerctl + +**Requires [Playerctl](https://github.com/acrisci/playerctl)**. Shows configurable information about currently playing track on a variety of players. Option to include control buttons. + +`pctl = Barr::Blocks::Playerctl.new player: "spotify", format: "${ARTIST} - ${TITLE} - ${BUTTONS}` + +| Option | Value | Description | Default | +| --- | --- | --- | --- | +| `format` | string | Configurable format for defining how the information is displayed. See table below for options | `"${ARTIST} - ${TRACK}"` | +| `player` | string | ID of the media app you want to control. Run `playerctl -l` to see what is available | '' | + +| Format Option | Description | +| --- | --- | +| `${ARTIST}` | Artist of currently playing track | +| `${ALBUM}` | Album of currently playing track | +| `${TITLE}` | Title of currently playing track | +| `${BUTTONS}` | Buttons to control playback | + #### Processes Shows the number of currently active processes on your system. @@ -359,7 +379,7 @@ Shows the number of currently active processes on your system. There are no `Processes` block specific configurable options. #### Rhythmbox - +**DEPRECATED** It's reccommended to use the `Playerctl` block instead of this. It's compatible with Rhythmbox and many other players, including Spotify. **Requires Rhythmbox and rhythmbox-client**. Shows currently playing artist and/or track, as well as control buttons. Control buttons use FontAwesome. `rb = Barr::Blocks::Rhythmbox.new buttons: false` diff --git a/barr.gemspec b/barr.gemspec index 2cdb0dd..513cc03 100644 --- a/barr.gemspec +++ b/barr.gemspec @@ -42,4 +42,5 @@ Gem::Specification.new do |spec| spec.requirements << "(Optional) Bspwm for Bspwm desktop support" spec.requirements << "(Optional) RhythmBox & rhythmbox-client" spec.requirements << "(Optional) FontAwesome font" + spec.requirements << "(Optional) playerctl" end diff --git a/lib/barr.rb b/lib/barr.rb index e435300..57342e3 100644 --- a/lib/barr.rb +++ b/lib/barr.rb @@ -16,6 +16,7 @@ require 'barr/blocks/i3' require 'barr/blocks/ip' require 'barr/blocks/mem' +require 'barr/blocks/playerctl' require 'barr/blocks/processes' require 'barr/blocks/rhythmbox' require 'barr/blocks/mpd' @@ -25,6 +26,7 @@ require 'barr/controllers/bbc_weather' require 'barr/controllers/http_grab' +require 'barr/controllers/playerctl' module Barr end diff --git a/lib/barr/blocks/playerctl.rb b/lib/barr/blocks/playerctl.rb new file mode 100644 index 0000000..7a439ab --- /dev/null +++ b/lib/barr/blocks/playerctl.rb @@ -0,0 +1,43 @@ +module Barr + module Blocks + class Playerctl < Block + attr_accessor :location + + def initialize opts={} + super + @format = opts[:format] || "${ARTIST} - ${TITLE}" + @player = opts[:player] || false + @btns = nil + end + + def config + opts = {id: @player, player: @player } + @controller = @manager.controller :Playerctl, opts + end + + def update! + op = @controller.output.merge buttons + @output = "#{format_string_from_hash(op)}" + end + + def buttons + if @btns.nil? + @btns = { + play_pause: wrap_button("\uf04b", "playerctl #{'-p #{@player} ' if @player}play-pause"), + next: wrap_button("\uf051", "playerctl #{'-p #{@player} ' if @player}next"), + previous: wrap_button("\uf048", "playerctl #{'-p #{@player} ' if @player}previous"), + } + + @btns.merge!(buttons: [ + @btns[:previous], + @btns[:play_pause], + @btns[:previous] + ].join(" ") + ) + end + + @btns + end + end + end +end diff --git a/lib/barr/controllers/playerctl.rb b/lib/barr/controllers/playerctl.rb new file mode 100644 index 0000000..629498e --- /dev/null +++ b/lib/barr/controllers/playerctl.rb @@ -0,0 +1,46 @@ +require 'json' + +module Barr + module Controllers + class Playerctl < Controller + + def initialize opts={} + super + @player = opts[:player] || "" + end + + def run! + @thread = Thread.new do + loop do + begin + op = {} + + op[:album] = sys_cmd 'album' + op[:artist] = sys_cmd 'artist' + op[:title] = sys_cmd 'title' + + File.write(filename, op.to_json) + + sleep 5 + rescue StandardError => e + STDERR.puts "thread error!" + STDERR.puts e.message + STDERR.puts e.backtrace + end + + end + end + @thread.run + end + + def sys_cmd key + if !@player.empty? + `playerctl -p #{@player} metadata #{key}` + else + `playerctl metadata #{key}` + end + end + + end + end +end diff --git a/spec/blocks/playerctl_spec.rb b/spec/blocks/playerctl_spec.rb new file mode 100644 index 0000000..fa3656f --- /dev/null +++ b/spec/blocks/playerctl_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' +require './spec/mocks/playerctl' + +RSpec.describe Barr::Blocks::PlayerctlBlockMock do + + describe '#initialize' do + it "sets default format" do + expect(subject.format).to eq("${ARTIST} - ${TITLE}") + end + end + + describe 'config' do + it "sets the controller" do + subject.config + expect(subject.controller).to be_a(Barr::Controllers::PlayerctlControllerMock) + end + end + + describe 'update' do + it "sets the output correctly" do + subject.format = "${ARTIST} - ${ALBUM} - ${NEXT}" + subject.config + subject.controller.update! + subject.update! + expect(subject.output).to eq("Slayer - Reign in Blood - %{A:playerctl next:}\uf051%{A}") + end + end + +end diff --git a/spec/mocks/playerctl.rb b/spec/mocks/playerctl.rb new file mode 100644 index 0000000..572bb70 --- /dev/null +++ b/spec/mocks/playerctl.rb @@ -0,0 +1,36 @@ +# coding: utf-8 +require 'barr/block' +require 'barr/controller' +require 'barr/blocks/playerctl' +require 'barr/controllers/playerctl' + +module Barr + module Controllers + class PlayerctlControllerMock < Barr::Controllers::Playerctl + def document + end + + def run! + end + + def update! + @output ||= {} + @output[:artist] = "Slayer" + @output[:title] = "Angel of Death" + @output[:album] = "Reign in Blood" + end + + end + end + + + module Blocks + class PlayerctlBlockMock < Barr::Blocks::Playerctl + def config + @controller = Barr::Controllers::PlayerctlControllerMock.new {} + end + end + end +end + + From 88cf5f0936a430fb101354adc91d764d0aac493e Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Sat, 3 Mar 2018 20:24:42 +0000 Subject: [PATCH 12/21] Added Rubocop configuration and corrected code as per recommendations --- .rubocop.yml | 30 +++++++++++++ Rakefile | 6 +-- barr.gemspec | 63 +++++++++++++-------------- bin/console | 6 +-- examples/all_in.rb | 18 ++++---- examples/barr_example.rb | 6 +-- examples/bsp.rb | 2 +- examples/conky.rb | 6 +-- examples/fizzbuzz.rb | 19 ++++----- examples/http_grab.rb | 10 ++--- examples/hue.rb | 11 +++-- examples/i3_cpu_mem.rb | 4 +- examples/rhythm.rb | 2 +- examples/time_and_date.rb | 0 examples/two_temperatures.rb | 0 exe/barr_example | 6 +-- exe/barr_open_url | 2 +- lib/barr/block.rb | 66 +++++++++++++++-------------- lib/barr/blocks/battery.rb | 19 ++++----- lib/barr/blocks/bbc_weather.rb | 14 +++--- lib/barr/blocks/bspwm.rb | 53 +++++++++++------------ lib/barr/blocks/clock.rb | 2 - lib/barr/blocks/conky.rb | 24 +++++------ lib/barr/blocks/cpu.rb | 14 +++--- lib/barr/blocks/hdd.rb | 2 - lib/barr/blocks/http_grab.rb | 8 ++-- lib/barr/blocks/hue_group.rb | 1 - lib/barr/blocks/hue_light.rb | 37 ++++++++-------- lib/barr/blocks/i3.rb | 12 +++--- lib/barr/blocks/ip.rb | 1 - lib/barr/blocks/mem.rb | 2 - lib/barr/blocks/mpd.rb | 7 ++- lib/barr/blocks/playerctl.rb | 23 +++++----- lib/barr/blocks/processes.rb | 3 +- lib/barr/blocks/rhythmbox.rb | 5 +-- lib/barr/blocks/separator.rb | 2 - lib/barr/blocks/temperature.rb | 4 +- lib/barr/blocks/whoami.rb | 2 - lib/barr/controller.rb | 17 ++++---- lib/barr/controllers/bbc_weather.rb | 38 ++++++++--------- lib/barr/controllers/http_grab.rb | 12 +++--- lib/barr/controllers/playerctl.rb | 11 ++--- lib/barr/manager.rb | 63 +++++++++++++++------------ lib/barr/version.rb | 2 +- spec/block_spec.rb | 52 +++++++++++------------ spec/blocks/battery_spec.rb | 27 ++++++------ spec/blocks/bbc_weather_spec.rb | 14 +++--- spec/blocks/bspwm_spec.rb | 48 ++++++++++----------- spec/blocks/clock_spec.rb | 2 - spec/blocks/conky_spec.rb | 20 ++++----- spec/blocks/cpu_spec.rb | 4 +- spec/blocks/hdd_spec.rb | 2 - spec/blocks/http_grab_spec.rb | 12 +++--- spec/blocks/hue_group_spec.rb | 25 +++++------ spec/blocks/hue_light_spec.rb | 25 +++++------ spec/blocks/i3_spec.rb | 5 +-- spec/blocks/ip_spec.rb | 2 - spec/blocks/mem_spec.rb | 2 - spec/blocks/mpd_spec.rb | 3 +- spec/blocks/playerctl_spec.rb | 12 +++--- spec/blocks/processes_spec.rb | 10 ++--- spec/blocks/rhythmbox_spec.rb | 3 +- spec/blocks/separator_spec.rb | 2 - spec/blocks/temperature_spec.rb | 4 +- spec/blocks/whoami_spec.rb | 2 - spec/manager_spec.rb | 2 - spec/mocks/bbc_weather.rb | 25 ++++------- spec/mocks/bspwm.rb | 4 +- spec/mocks/http_grab.rb | 17 +++----- spec/mocks/i3.rb | 4 +- spec/mocks/playerctl.rb | 18 +++----- 71 files changed, 454 insertions(+), 527 deletions(-) create mode 100644 .rubocop.yml mode change 100644 => 100755 bin/console mode change 100644 => 100755 examples/all_in.rb mode change 100644 => 100755 examples/barr_example.rb mode change 100644 => 100755 examples/bsp.rb mode change 100644 => 100755 examples/conky.rb mode change 100644 => 100755 examples/fizzbuzz.rb mode change 100644 => 100755 examples/http_grab.rb mode change 100644 => 100755 examples/hue.rb mode change 100644 => 100755 examples/i3_cpu_mem.rb mode change 100644 => 100755 examples/rhythm.rb mode change 100644 => 100755 examples/time_and_date.rb mode change 100644 => 100755 examples/two_temperatures.rb diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..44f3282 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,30 @@ +Metrics/LineLength: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/FormatStringToken: + Enabled: false + +Metrics/AbcSize: + Enabled: false + +Metrics/MethodLength: + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false + +Metrics/CyclomaticComplexity: + Enabled: false + +Lint/InterpolationCheck: + Enabled: false + +Metrics/BlockLength: + Enabled: false + +AllCops: + Exclude: + - spec/**/* \ No newline at end of file diff --git a/Rakefile b/Rakefile index b7e9ed5..4c774a2 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,6 @@ -require "bundler/gem_tasks" -require "rspec/core/rake_task" +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) -task :default => :spec +task default: :spec diff --git a/barr.gemspec b/barr.gemspec index 513cc03..0956a95 100644 --- a/barr.gemspec +++ b/barr.gemspec @@ -1,46 +1,47 @@ -# coding: utf-8 + lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'barr/version' Gem::Specification.new do |spec| - spec.name = "barr" + spec.name = 'barr' spec.version = Barr::VERSION - spec.authors = ["Dave Russell"] - spec.email = ["dave.kerr@gmail.com"] + spec.authors = ['Dave Russell'] + spec.email = ['dave.kerr@gmail.com'] - spec.summary = "Barr is a status line generator for use with Lemonbar" - spec.homepage = "https://github.com/OkayDave/barr" - spec.license = "MIT" + spec.summary = 'Barr is a status line generator for use with Lemonbar' + spec.homepage = 'https://github.com/OkayDave/barr' + spec.license = 'MIT' # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or # delete this section to allow pushing this gem to any host. - if spec.respond_to?(:metadata) + if spec.respond_to?(:metadata) # rubocop:disable Style/GuardClause else - raise "RubyGems 2.0 or newer is required to protect against public gem pushes." + raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' end spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } - spec.bindir = "exe" - spec.executables = `git ls-files -- exe/*`.split("\n").map{ |f| File.basename(f) } - spec.require_paths = ["lib"] - - spec.add_development_dependency "bundler", "~> 1.11" - spec.add_development_dependency "rake", "~> 10.0" - spec.add_development_dependency "rspec", "~> 3.0" - spec.add_development_dependency "timecop", "~> 0.8.0" - spec.add_development_dependency "pry-byebug", "~> 3.4" - - spec.add_runtime_dependency "i3ipc", "0.2.0" - spec.add_runtime_dependency "weather-api", "1.2.0" - spec.add_runtime_dependency "nokogiri", "~> 1.6" - spec.add_runtime_dependency "poltergeist", "~> 1.11" - spec.add_runtime_dependency "hue", "~> 0.2" - - spec.requirements << "Lemonbar with XFT support (https://github.com/krypt-n/bar)" - spec.requirements << "(Optional) I3 for Workspace support" - spec.requirements << "(Optional) Bspwm for Bspwm desktop support" - spec.requirements << "(Optional) RhythmBox & rhythmbox-client" - spec.requirements << "(Optional) FontAwesome font" - spec.requirements << "(Optional) playerctl" + spec.bindir = 'exe' + spec.executables = `git ls-files -- exe/*`.split("\n").map { |f| File.basename(f) } + spec.require_paths = ['lib'] + + spec.add_development_dependency 'bundler', '~> 1.11' + spec.add_development_dependency 'pry-byebug', '~> 3.4' + spec.add_development_dependency 'rake', '~> 10.0' + spec.add_development_dependency 'rspec', '~> 3.0' + spec.add_development_dependency 'rubocop', '~> 0.52.1' + spec.add_development_dependency 'timecop', '~> 0.8.0' + + spec.add_runtime_dependency 'hue', '~> 0.2' + spec.add_runtime_dependency 'i3ipc', '0.2.0' + spec.add_runtime_dependency 'nokogiri', '~> 1.6' + spec.add_runtime_dependency 'poltergeist', '~> 1.11' + spec.add_runtime_dependency 'weather-api', '1.2.0' + + spec.requirements << 'Lemonbar with XFT support (https://github.com/krypt-n/bar)' + spec.requirements << '(Optional) I3 for Workspace support' + spec.requirements << '(Optional) Bspwm for Bspwm desktop support' + spec.requirements << '(Optional) RhythmBox & rhythmbox-client' + spec.requirements << '(Optional) FontAwesome font' + spec.requirements << '(Optional) playerctl' end diff --git a/bin/console b/bin/console old mode 100644 new mode 100755 index 5e0fd8d..c3bae77 --- a/bin/console +++ b/bin/console @@ -1,7 +1,7 @@ #!/usr/bin/env ruby -require "bundler/setup" -require "barr" +require 'bundler/setup' +require 'barr' # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. @@ -10,5 +10,5 @@ require "barr" # require "pry" # Pry.start -require "irb" +require 'irb' IRB.start diff --git a/examples/all_in.rb b/examples/all_in.rb old mode 100644 new mode 100755 index 3a448a3..671eefb --- a/examples/all_in.rb +++ b/examples/all_in.rb @@ -9,7 +9,7 @@ i3 = Barr::Blocks::I3.new(fgcolor: '#FFF', bgcolor: '#145266', - focus_markers: %w(> <), + focus_markers: %w[> <], align: :r, icon: "\uf009", interval: 0.2) @@ -39,7 +39,7 @@ icon: "\uf0c2 Philadelphia: ", interval: 1500) -cpu = Barr::Blocks::CPU.new icon: "\uf1fe", format: "${LOAD}% ${TEMP}" +cpu = Barr::Blocks::CPU.new icon: "\uf1fe", format: '${LOAD}% ${TEMP}' mem = Barr::Blocks::Mem.new bgcolor: '#333333' @@ -47,12 +47,12 @@ local = Barr::Blocks::IP.new bgcolor: '#937739', align: :r, icon: "\uf1ce" -office_lights = Barr::Blocks::HueGroup.new id: "3", - icon: "\uf1ad", - format: "${OFF} ${ON:H-1,H-65535,B-255} ${ON:B-120,T-dim}", - align: :r, - bgcolor: '#0c1e3a', - fcolor: '#EEEEEE' +office_lights = Barr::Blocks::HueGroup.new id: '3', + icon: "\uf1ad", + format: '${OFF} ${ON:H-1,H-65535,B-255} ${ON:B-120,T-dim}', + align: :r, + bgcolor: '#0c1e3a', + fcolor: '#EEEEEE' # Left @man.add artist @man.add song @@ -61,7 +61,7 @@ @man.add mem @man.add hdd -# Right +# Right @man.add office_lights @man.add i3 @man.add local diff --git a/examples/barr_example.rb b/examples/barr_example.rb old mode 100644 new mode 100755 index 75b5ead..cd3e2d3 --- a/examples/barr_example.rb +++ b/examples/barr_example.rb @@ -5,13 +5,13 @@ require 'barr' # Create a new manager instance. -# The manager is responsible for organising the blocks and delivering their output to lemonbar +# The manager is responsible for organising the blocks and delivering their output to lemonbar @manager = Barr::Manager.new # Add a 'Whoami' block. This just outputs logged in username # Give it a peach background, grey text and updates every 10000 seconds # It will be aligned to the left of the bar -@manager.add Barr::Blocks::Whoami.new(bgcolor: '#FFAAAA', fgcolor: '#333333', interval: 10000) +@manager.add Barr::Blocks::Whoami.new(bgcolor: '#FFAAAA', fgcolor: '#333333', interval: 10_000) # Add a 'Clock' block. # Clocks can be formatted in the type strftime fashion. This example outputs the current Hour and Minute @@ -20,13 +20,11 @@ # If FontAwesome font is available to lemonbar, it will be prepended with a clock icon. @manager.add Barr::Blocks::Clock.new(icon: "\uf017", format: '%H:%M', align: :c, interval: 1) - # Add a 'CPU' block. This shows the current CPU usage (averaged across all cores if present) # It will be aligned to the right side of of the bar # As an interval is not provided, it will update every 5 seconds. # It will be prepended with the text 'Cpu:' @manager.add Barr::Blocks::CPU.new(icon: 'Cpu:', align: :r) - # Tell the manager to run the loop. This will continue indefinitely, outputing the data ready to be piped in to lemonbar. @manager.run! diff --git a/examples/bsp.rb b/examples/bsp.rb old mode 100644 new mode 100755 index e7c8a51..b68a5c2 --- a/examples/bsp.rb +++ b/examples/bsp.rb @@ -5,7 +5,7 @@ @man = Barr::Manager.new -bsp = Barr::Blocks::Bspwm.new icon: "\uf108", bgcolor: '#114152', fgcolor: '#DAC1DE', align: :l, focus_markers: ['',''], invert_focus_colors: true, interval: 1 +bsp = Barr::Blocks::Bspwm.new icon: "\uf108", bgcolor: '#114152', fgcolor: '#DAC1DE', align: :l, focus_markers: ['', ''], invert_focus_colors: true, interval: 1 bsp_df = Barr::Blocks::Bspwm.new align: :r, interval: 1 diff --git a/examples/conky.rb b/examples/conky.rb old mode 100644 new mode 100755 index f6102c5..5fc3f6d --- a/examples/conky.rb +++ b/examples/conky.rb @@ -5,9 +5,9 @@ @man = Barr::Manager.new -netspeed = Barr::Blocks::Conky.new text: "${downspeedf enp3s0} ${upspeedf enp3s0}", align: :l, interval: 1 -cpu = Barr::Blocks::Conky.new text: "${cpubar}", align: :c, interval: 1 -swap = Barr::Blocks::Conky.new text: "${swap}", align: :r, interval: 1 +netspeed = Barr::Blocks::Conky.new text: '${downspeedf enp3s0} ${upspeedf enp3s0}', align: :l, interval: 1 +cpu = Barr::Blocks::Conky.new text: '${cpubar}', align: :c, interval: 1 +swap = Barr::Blocks::Conky.new text: '${swap}', align: :r, interval: 1 @man.add netspeed @man.add cpu diff --git a/examples/fizzbuzz.rb b/examples/fizzbuzz.rb old mode 100644 new mode 100755 index 0de887b..1fb71da --- a/examples/fizzbuzz.rb +++ b/examples/fizzbuzz.rb @@ -12,19 +12,18 @@ def initialize(opts = {}) def update! @count += 1 - @output = if (@count % 3 == 0) && (@count % 5 == 0) - 'FizzBuzz' - elsif @count % 3 == 0 - 'Fizz' - elsif @count % 5 == 0 - 'Buzz' - else - @count.to_s - end + @output = if (@count % 3).zero? && (@count % 5).zero? + 'FizzBuzz' + elsif (@count % 3).zero? + 'Fizz' + elsif (@count % 5).zero? + 'Buzz' + else + @count.to_s + end end end - clock = Barr::Blocks::Clock.new align: :r counter = FizzBuzz.new align: :l, bgcolor: '#8CB8FF', fgcolor: '#333333', icon: "\uf1ec", interval: 1 diff --git a/examples/http_grab.rb b/examples/http_grab.rb old mode 100644 new mode 100755 index b988728..4aa92a2 --- a/examples/http_grab.rb +++ b/examples/http_grab.rb @@ -5,11 +5,11 @@ @man = Barr::Manager.new -grab = Barr::Blocks::HTTPGrab.new url: "http://www.bbc.co.uk/news", - icon: "Top News:", - type: :css, - selector: "span.most-popular-list-item__headline", - link: true +grab = Barr::Blocks::HTTPGrab.new url: 'http://www.bbc.co.uk/news', + icon: 'Top News:', + type: :css, + selector: 'span.most-popular-list-item__headline', + link: true @man.add grab diff --git a/examples/hue.rb b/examples/hue.rb old mode 100644 new mode 100755 index a8ef311..d2a9d27 --- a/examples/hue.rb +++ b/examples/hue.rb @@ -5,14 +5,13 @@ @man = Barr::Manager.new -light = Barr::Blocks::HueLight.new id: "6", +light = Barr::Blocks::HueLight.new id: '6', icon: "\uf0eb", - format: "${OFF:T-Turn Off} ${ON} ${ON:B-50,T-Dim 25%,H-34332} ${ON:A-lselect,T-Alert!,H-65535}" - -group = Barr::Blocks::HueGroup.new id: "3", - icon: "\uf1ad", - format: "${OFF:T-Turn Off} ${ON:H-1,T-Turn On}" + format: '${OFF:T-Turn Off} ${ON} ${ON:B-50,T-Dim 25%,H-34332} ${ON:A-lselect,T-Alert!,H-65535}' +group = Barr::Blocks::HueGroup.new id: '3', + icon: "\uf1ad", + format: '${OFF:T-Turn Off} ${ON:H-1,T-Turn On}' @man.add light @man.add group diff --git a/examples/i3_cpu_mem.rb b/examples/i3_cpu_mem.rb old mode 100644 new mode 100755 index 14997d6..6b33c08 --- a/examples/i3_cpu_mem.rb +++ b/examples/i3_cpu_mem.rb @@ -5,9 +5,9 @@ @man = Barr::Manager.new -i3 = Barr::Blocks::I3.new icon: "\uf108", bgcolor: '#114152', fgcolor: '#DAC1DE', align: :l, focus_markers: ["| \uf0a4",' |'], invert_focus_colors: true, interval: 0.2 +i3 = Barr::Blocks::I3.new icon: "\uf108", bgcolor: '#114152', fgcolor: '#DAC1DE', align: :l, focus_markers: ["| \uf0a4", ' |'], invert_focus_colors: true, interval: 0.2 -cpu = Barr::Blocks::CPU.new icon: "\uf108 CPU:", bgcolor: '#491A5E', align: :r, format: "${LOAD}" +cpu = Barr::Blocks::CPU.new icon: "\uf108 CPU:", bgcolor: '#491A5E', align: :r, format: '${LOAD}' mem = Barr::Blocks::Mem.new icon: 'RAM:', align: :r, bgcolor: '#2F113D' diff --git a/examples/rhythm.rb b/examples/rhythm.rb old mode 100644 new mode 100755 index d9d0db9..200c47a --- a/examples/rhythm.rb +++ b/examples/rhythm.rb @@ -9,7 +9,7 @@ title = Barr::Blocks::Rhythmbox.new align: :l, artist: false, buttons: false, bgcolor: '#0D450A' -btns = Barr::Blocks::Rhythmbox.new align: :r, artist: false, title: false, bgcolor: '#033B00', interval: 10000 +btns = Barr::Blocks::Rhythmbox.new align: :r, artist: false, title: false, bgcolor: '#033B00', interval: 10_000 @man.add artist @man.add title diff --git a/examples/time_and_date.rb b/examples/time_and_date.rb old mode 100644 new mode 100755 diff --git a/examples/two_temperatures.rb b/examples/two_temperatures.rb old mode 100644 new mode 100755 diff --git a/exe/barr_example b/exe/barr_example index 6bd90b8..45a015f 100755 --- a/exe/barr_example +++ b/exe/barr_example @@ -5,13 +5,13 @@ require 'rubygems' require 'barr' # Create a new manager instance. -# The manager is responsible for organising the blocks and delivering their output to lemonbar +# The manager is responsible for organising the blocks and delivering their output to lemonbar @manager = Barr::Manager.new # Add a 'Whoami' block. This just outputs logged in username # Give it a peach background, grey text and updates every 10000 seconds # It will be aligned to the left of the bar -@manager.add_block Barr::Blocks::Whoami.new(bcolor: '#FFAAAA', fcolor: '#333333', interval: 10000) +@manager.add_block Barr::Blocks::Whoami.new(bcolor: '#FFAAAA', fcolor: '#333333', interval: 10_000) # Add a 'Clock' block. # Clocks can be formatted in the type strftime fashion. This example outputs the current Hour and Minute @@ -20,13 +20,11 @@ require 'barr' # If FontAwesome font is available to lemonbar, it will be prepended with a clock icon. @manager.add_block Barr::Blocks::Clock.new(icon: "\uf017", format: '%H:%M', align: :c, interval: 1) - # Add a 'CPU' block. This shows the current CPU usage (averaged across all cores if present) # It will be aligned to the right side of of the bar # As an interval is not provided, it will update every 5 seconds. # It will be prepended with the text 'Cpu:' @manager.add_block Barr::Blocks::CPU.new(icon: 'Cpu:', align: :r) - # Tell the manager to run the loop. This will continue indefinitely, outputing the data ready to be piped in to lemonbar. @manager.run! diff --git a/exe/barr_open_url b/exe/barr_open_url index 40ef241..53a767f 100755 --- a/exe/barr_open_url +++ b/exe/barr_open_url @@ -2,5 +2,5 @@ require 'rubygems' -cmd = ARGV.join('://').gsub("\\","") +cmd = ARGV.join('://').delete('\\') `xdg-open #{cmd}` diff --git a/lib/barr/block.rb b/lib/barr/block.rb index 8cdc5ce..1f9c8ab 100644 --- a/lib/barr/block.rb +++ b/lib/barr/block.rb @@ -31,54 +31,57 @@ def draw "#{colors} #{icon} #{@output} #{reset_colors}" end - def destroy! - end - - def update! - end + def destroy!; end + + def update!; end def tmp_filename - @tmp_filename ||= "/tmp/barr-#{SecureRandom.uuid}-#{self.class.name.gsub(/::/, "-")}-#{SecureRandom.urlsafe_base64}" - return @tmp_filename + @tmp_filename ||= "/tmp/barr-#{SecureRandom.uuid}-#{self.class.name.gsub(/::/, '-')}-#{SecureRandom.urlsafe_base64}" + @tmp_filename end - def wrap_button text, action + def wrap_button(text, action) "%{A:#{action}:}#{text}%{A}" end - def format_string_from_hash(hash, sender=nil) - formatted = @format.clone + def format_string_from_hash(hash, sender = nil) + formatted = @format.clone matches = @format.scan(/([\$][\{](\w+)(:?([^:\}]+)?)[\}])/) - # binding.pry matches.each do |match| - key = match[1].downcase.to_sym - if hash.has_key? key - if !match[3].nil? && sender && sender.respond_to?(:additions_for_format) - sub = sender.additions_for_format(key, match[3]) - else - sub = hash[key] - end - else - sub = "" - end + key = match[1].downcase.to_sym + sub = if hash.key? key + if !match[3].nil? && sender && sender.respond_to?(:additions_for_format) + sender.additions_for_format(key, match[3]) + else + hash[key] + end + else + '' + end formatted.gsub! match[0], sub end - return formatted + formatted end # Backwards compatiblity methods. # can't use alias/alias_method as they don't - # trickle down to subclasses - def update; update!; end - def destroy; destroy!; end - - def reassign_deprecated_option opts, old, new - if opts[new].nil? && !opts[old].nil? - STDERR.puts "Warning: #{self.class.name}'s '#{old}' option will soon be deprecated in favour of '#{new}'. \n Please update your script." - opts[new] = opts[old] - end + # trickle down to subclasses + def update + update! + end + + def destroy + destroy! + end + + def reassign_deprecated_option(opts, old, new) + return unless opts[new].nil? + return if opts[old].nil? + + STDERR.puts "Warning: #{self.class.name}'s '#{old}' option will soon be deprecated in favour of '#{new}'. \n Please update your script." + opts[new] = opts[old] end private @@ -90,6 +93,5 @@ def reset_colors def invert_colors '%{R}' end - end end diff --git a/lib/barr/blocks/battery.rb b/lib/barr/blocks/battery.rb index 9260ca2..aabbc51 100644 --- a/lib/barr/blocks/battery.rb +++ b/lib/barr/blocks/battery.rb @@ -2,27 +2,26 @@ module Barr module Blocks - class Battery < Block attr_reader :show_remaining - - def initialize opts={} + + def initialize(opts = {}) super - @show_remaining = opts[:show_remaining].nil? ? true : opts[:show_remaining] + @show_remaining = opts[:show_remaining].nil? ? true : opts[:show_remaining] end def update! - if @show_remaining == true - @output = battery_remaining - else - @output = battery_no_remaining - end + @output = if @show_remaining == true + battery_remaining + else + battery_no_remaining + end end def battery_remaining `acpi | cut -d ',' -f 2-3`.chomp end - + def battery_no_remaining `acpi | cut -d ',' -f 2`.chomp end diff --git a/lib/barr/blocks/bbc_weather.rb b/lib/barr/blocks/bbc_weather.rb index 4ee207d..21affa8 100644 --- a/lib/barr/blocks/bbc_weather.rb +++ b/lib/barr/blocks/bbc_weather.rb @@ -3,25 +3,23 @@ module Blocks class BBCWeather < Block attr_accessor :location - def initialize opts={} + def initialize(opts = {}) super @location = opts[:location] - @format = opts[:format] || "${TEMPERATURE} - ${SUMMARY}" - @temp_unit = opts[:temp_unit] || "c" - @speed_unit = opts[:speed_unit] || "mph" + @format = opts[:format] || '${TEMPERATURE} - ${SUMMARY}' + @temp_unit = opts[:temp_unit] || 'c' + @speed_unit = opts[:speed_unit] || 'mph' end def config - opts = {id: @location, temp_unit: @temp_unit, speed_unit: @speed_unit } - @controller = @manager.controller :BBCWeather, opts + opts = { id: @location, temp_unit: @temp_unit, speed_unit: @speed_unit } + @controller = @manager.controller :BBCWeather, opts end def update! op = @controller.output @output = "%{A:barr_open_url http www.bbc.co.uk\/weather\/#{@location}:}#{format_string_from_hash(op)}%{A}" end - - end end end diff --git a/lib/barr/blocks/bspwm.rb b/lib/barr/blocks/bspwm.rb index 5228ed1..5b985a5 100644 --- a/lib/barr/blocks/bspwm.rb +++ b/lib/barr/blocks/bspwm.rb @@ -3,64 +3,61 @@ module Barr module Blocks - class Bspwm < Block - attr_reader :monitor, :tree, :focus_markers attr_accessor :invert_focus_colors - def initialize opts={} + def initialize(opts = {}) super @monitor = opts[:monitor] || first_monitor @invert_focus_colors = opts[:invert_focus_colors] || false - @focus_markers = opts[:focus_markers] || %w(> <) + @focus_markers = opts[:focus_markers] || %w[> <] end def update! @tree = nil op = [] - focused = "" - bsp_tree["monitors"].each do |monitor| - next if (monitor["id"] != @monitor) && (monitor["name"] != @monitor) - focused = monitor["focusedDesktopId"] - monitor["desktops"].each do |desktop| - if desktop["id"] == focused - op << focused_desktop(desktop) - else - op << unfocused_desktop(desktop) - end + focused = '' + bsp_tree['monitors'].each do |monitor| + next if (monitor['id'] != @monitor) && (monitor['name'] != @monitor) + focused = monitor['focusedDesktopId'] + monitor['desktops'].each do |desktop| + op << if desktop['id'] == focused + focused_desktop(desktop) + else + unfocused_desktop(desktop) + end end - end - @output = op.join(" ") + @output = op.join(' ') end def bsp_tree @tree ||= JSON.parse(sys_cmd) end - def focused_desktop desktop - op = "" + def focused_desktop(desktop) + op = '' op += invert_colors if @invert_focus_colors - op += @focus_markers[0] + " " - op += desktop["name"] - op += " " + @focus_markers[1] + op += @focus_markers[0] + ' ' + op += desktop['name'] + op += ' ' + @focus_markers[1] op += invert_colors if @invert_focus_colors op end - def unfocused_desktop desktop - op = "" - op += "%{A:bspc desktop -f #{desktop["id"]}:} " - op += "#{desktop["name"]}" - op += " %{A}" + def unfocused_desktop(desktop) + op = '' + op += "%{A:bspc desktop -f #{desktop['id']}:} " + op += (desktop['name']).to_s + op += ' %{A}' - return op + op end def first_monitor - bsp_tree["monitors"].first["id"] + bsp_tree['monitors'].first['id'] end def sys_cmd diff --git a/lib/barr/blocks/clock.rb b/lib/barr/blocks/clock.rb index 8d77a9c..3bf243b 100644 --- a/lib/barr/blocks/clock.rb +++ b/lib/barr/blocks/clock.rb @@ -3,7 +3,6 @@ module Barr module Blocks class Clock < Block - def initialize(opts = {}) super @format = opts[:format] || '%H:%M %d %b %Y' @@ -12,7 +11,6 @@ def initialize(opts = {}) def update! @output = Time.now.strftime(@format) end - end end end diff --git a/lib/barr/blocks/conky.rb b/lib/barr/blocks/conky.rb index ecbcba3..dc209be 100644 --- a/lib/barr/blocks/conky.rb +++ b/lib/barr/blocks/conky.rb @@ -2,10 +2,9 @@ module Barr module Blocks - class Conky < Block attr_reader :text - def initialize opts={} + def initialize(opts = {}) super @text = opts[:text] @@ -18,25 +17,25 @@ def update! end def sys_cmd - `tail -n1 #{@filename_output}`.chomp.gsub("#","\u2588") + `tail -n1 #{@filename_output}`.chomp.tr('#', "\u2588") end def write_template - @conky_template = " - out_to_x no + @conky_template = " + out_to_x no out_to_console yes - own_window no - update_interval #{@interval.to_f.to_s} + own_window no + update_interval #{@interval.to_f} TEXT - #{@text} + #{@text} ".gsub(/^\s+/, '').chomp! - @filename_template = tmp_filename+"-conky" - @filename_output = tmp_filename+"-output" + @filename_template = tmp_filename + '-conky' + @filename_output = tmp_filename + '-output' - STDERR.puts "@conky_template: " + STDERR.puts '@conky_template: ' STDERR.puts @conky_template - File.open(@filename_template, "w") { |f| f.write(@conky_template) } + File.open(@filename_template, 'w') { |f| f.write(@conky_template) } end def spawn_conky @@ -48,7 +47,6 @@ def destroy! `rm #{@filename_template}` `rm #{@filename_output}` end - end end end diff --git a/lib/barr/blocks/cpu.rb b/lib/barr/blocks/cpu.rb index fb847eb..804047e 100644 --- a/lib/barr/blocks/cpu.rb +++ b/lib/barr/blocks/cpu.rb @@ -1,23 +1,22 @@ -# coding: utf-8 + require 'barr/block' module Barr module Blocks class CPU < Block - - def initialize opts={} + def initialize(opts = {}) super - @format = opts[:format] || "${LOAD}" + @format = opts[:format] || '${LOAD}' end def update! op = {} - op[:load] = load_sys_cmd.to_f.round(2).to_s + "%" - op[:temp] = (temp_sys_cmd.to_f.round(2) / 1000).to_s + "°" + op[:load] = load_sys_cmd.to_f.round(2).to_s + '%' + op[:temp] = (temp_sys_cmd.to_f.round(2) / 1000).to_s + '°' @output = format_string_from_hash(op) end - + private def load_sys_cmd @@ -27,7 +26,6 @@ def load_sys_cmd def temp_sys_cmd `cat /sys/class/thermal/thermal_zone0/temp` end - end Cpu = CPU diff --git a/lib/barr/blocks/hdd.rb b/lib/barr/blocks/hdd.rb index 4f6beff..98dc1c9 100644 --- a/lib/barr/blocks/hdd.rb +++ b/lib/barr/blocks/hdd.rb @@ -3,7 +3,6 @@ module Barr module Blocks class HDD < Block - def initialize(opts = {}) super @@ -21,7 +20,6 @@ def update! def sys_cmd `df -h | grep #{@device} | awk '{printf "%s %s %s", $2, $3, $5}'`.chomp end - end Hdd = HDD diff --git a/lib/barr/blocks/http_grab.rb b/lib/barr/blocks/http_grab.rb index ca72dbd..320f35b 100644 --- a/lib/barr/blocks/http_grab.rb +++ b/lib/barr/blocks/http_grab.rb @@ -3,22 +3,22 @@ module Blocks class HTTPGrab < Block attr_accessor :url, :type, :selector, :link - def initialize opts={} + def initialize(opts = {}) super @url = opts[:url] @type = opts[:type] || :css @selector = opts[:selector] - @link = !!opts[:link] + @link = opts[:link].nil? ? false : opts[:link] end def config - opts = {url: @url, type: @type, selector: @selector} + opts = { url: @url, type: @type, selector: @selector } @controller = @manager.controller :HTTPGrab, opts end def update! @output = @controller.output[:text] - @output = "%{A:barr_open_url #{@url.gsub("://"," ").gsub("/","\/")}:}#{@output}%{A}" if @link + @output = "%{A:barr_open_url #{@url.gsub('://', ' ').tr('/', "\/")}:}#{@output}%{A}" if @link end end end diff --git a/lib/barr/blocks/hue_group.rb b/lib/barr/blocks/hue_group.rb index 40d85db..3a187b4 100644 --- a/lib/barr/blocks/hue_group.rb +++ b/lib/barr/blocks/hue_group.rb @@ -10,7 +10,6 @@ class HueGroup < Barr::Blocks::HueLight def sys_cmd "hue group #{@id}" end - end end end diff --git a/lib/barr/blocks/hue_light.rb b/lib/barr/blocks/hue_light.rb index 0ba4af1..aae3c85 100644 --- a/lib/barr/blocks/hue_light.rb +++ b/lib/barr/blocks/hue_light.rb @@ -9,7 +9,7 @@ def initialize(opts = {}) super @id = opts[:id] - @format = opts[:format] || "${ON} ${OFF}" + @format = opts[:format] || '${ON} ${OFF}' end def update! @@ -18,17 +18,17 @@ def update! def additions_for_format(key, option_str) agg = [] - text = "" + text = '' options = option_str.split(/(? <) - @invert_focus_colors = opts[:invert_focus_colors] || false + @focus_markers = opts[:focus_markers] || %w[> <] + @invert_focus_colors = opts[:invert_focus_colors] || false @i3 = i3_connection end @@ -20,13 +19,13 @@ def update! if wsp.focused "#{invert_colors if @invert_focus_colors}#{l_marker}#{wsp.name}#{r_marker}#{invert_colors if @invert_focus_colors}" else - "%{A:barr_i3ipc \"workspace #{wsp.name.gsub(":","\\:")}\":} #{wsp.name} %{A}" + "%{A:barr_i3ipc \"workspace #{wsp.name.gsub(':', '\\:')}\":} #{wsp.name} %{A}" end end @output = @workspaces.join('') - rescue => e - if e.message.match(/broken pipe/i) + rescue StandardError => e + if e.message =~ /broken pipe/i # rubocop:disable Style/GuardClause @i3 = i3_connection else raise @@ -50,7 +49,6 @@ def l_marker def r_marker @focus_markers[1] end - end end end diff --git a/lib/barr/blocks/ip.rb b/lib/barr/blocks/ip.rb index 33bed5f..0559b91 100644 --- a/lib/barr/blocks/ip.rb +++ b/lib/barr/blocks/ip.rb @@ -3,7 +3,6 @@ module Barr module Blocks class IP < Block - attr_reader :device def initialize(opts = {}) diff --git a/lib/barr/blocks/mem.rb b/lib/barr/blocks/mem.rb index 8946c29..4b9eb00 100644 --- a/lib/barr/blocks/mem.rb +++ b/lib/barr/blocks/mem.rb @@ -3,7 +3,6 @@ module Barr module Blocks class Mem < Block - def update! @output = sys_cmd end @@ -15,5 +14,4 @@ def sys_cmd end end end - end diff --git a/lib/barr/blocks/mpd.rb b/lib/barr/blocks/mpd.rb index 7e75201..3631574 100644 --- a/lib/barr/blocks/mpd.rb +++ b/lib/barr/blocks/mpd.rb @@ -22,7 +22,7 @@ def update! op = [] if @view_opts[:artist] || @view_opts[:title] - if(running?) + if running? info = sys_cmd.split(' - ') if @view_opts[:artist] && @view_opts[:title] @@ -40,14 +40,13 @@ def update! op << buttons if @view_opts[:buttons] @output = op.join(' ') - end def running? - if `pgrep mopidy`.chomp.length != 0 + if !`pgrep mopidy`.chomp.empty? true else - `pgrep mpd`.chomp.length != 0 + !`pgrep mpd`.chomp.empty? end end diff --git a/lib/barr/blocks/playerctl.rb b/lib/barr/blocks/playerctl.rb index 7a439ab..cc862c2 100644 --- a/lib/barr/blocks/playerctl.rb +++ b/lib/barr/blocks/playerctl.rb @@ -3,21 +3,21 @@ module Blocks class Playerctl < Block attr_accessor :location - def initialize opts={} + def initialize(opts = {}) super - @format = opts[:format] || "${ARTIST} - ${TITLE}" + @format = opts[:format] || '${ARTIST} - ${TITLE}' @player = opts[:player] || false @btns = nil end def config - opts = {id: @player, player: @player } - @controller = @manager.controller :Playerctl, opts + opts = { id: @player, player: @player } + @controller = @manager.controller :Playerctl, opts end def update! op = @controller.output.merge buttons - @output = "#{format_string_from_hash(op)}" + @output = format_string_from_hash(op).to_s end def buttons @@ -25,15 +25,14 @@ def buttons @btns = { play_pause: wrap_button("\uf04b", "playerctl #{'-p #{@player} ' if @player}play-pause"), next: wrap_button("\uf051", "playerctl #{'-p #{@player} ' if @player}next"), - previous: wrap_button("\uf048", "playerctl #{'-p #{@player} ' if @player}previous"), + previous: wrap_button("\uf048", "playerctl #{'-p #{@player} ' if @player}previous") } - @btns.merge!(buttons: [ - @btns[:previous], - @btns[:play_pause], - @btns[:previous] - ].join(" ") - ) + @btns[:buttons] = [ + @btns[:previous], + @btns[:play_pause], + @btns[:previous] + ].join(' ') end @btns diff --git a/lib/barr/blocks/processes.rb b/lib/barr/blocks/processes.rb index 72883e3..f876e26 100644 --- a/lib/barr/blocks/processes.rb +++ b/lib/barr/blocks/processes.rb @@ -2,10 +2,9 @@ module Barr module Blocks - class Processes < Block def update! - @output = sys_cmd + @output = sys_cmd end def sys_cmd diff --git a/lib/barr/blocks/rhythmbox.rb b/lib/barr/blocks/rhythmbox.rb index df1fa40..48e4861 100644 --- a/lib/barr/blocks/rhythmbox.rb +++ b/lib/barr/blocks/rhythmbox.rb @@ -22,7 +22,7 @@ def update! op = [] if @view_opts[:artist] || @view_opts[:title] - if(running?) + if running? info = sys_cmd.split(' - ') if @view_opts[:artist] && @view_opts[:title] @@ -40,11 +40,10 @@ def update! op << buttons if @view_opts[:buttons] @output = op.join(' ') - end def running? - `pgrep rhythmbox`.chomp.length != 0 + !`pgrep rhythmbox`.chomp.empty? end def buttons diff --git a/lib/barr/blocks/separator.rb b/lib/barr/blocks/separator.rb index 6740113..b678403 100644 --- a/lib/barr/blocks/separator.rb +++ b/lib/barr/blocks/separator.rb @@ -3,7 +3,6 @@ module Barr module Blocks class Separator < Block - def initialize(opts = {}) super @symbol = opts[:symbol] || '|' @@ -12,7 +11,6 @@ def initialize(opts = {}) def update! @output = @symbol end - end end end diff --git a/lib/barr/blocks/temperature.rb b/lib/barr/blocks/temperature.rb index 401f99d..6b36aec 100644 --- a/lib/barr/blocks/temperature.rb +++ b/lib/barr/blocks/temperature.rb @@ -1,11 +1,10 @@ -# coding: utf-8 + require 'weather-api' require 'barr/block' module Barr module Blocks class Temperature < Block - attr_reader :location def initialize(opts = {}) @@ -29,7 +28,6 @@ def weather def weather_units @unit == 'F' ? Weather::Units::FAHRENHEIT : Weather::Units::CELSIUS end - end end end diff --git a/lib/barr/blocks/whoami.rb b/lib/barr/blocks/whoami.rb index 3b08079..9a8a0e5 100644 --- a/lib/barr/blocks/whoami.rb +++ b/lib/barr/blocks/whoami.rb @@ -3,7 +3,6 @@ module Barr module Blocks class Whoami < Block - def initialize(opts = {}) super end @@ -17,7 +16,6 @@ def update! def sys_cmd `whoami`.chomp end - end WhoAmI = Whoami diff --git a/lib/barr/controller.rb b/lib/barr/controller.rb index 166d362..a0d9cc7 100644 --- a/lib/barr/controller.rb +++ b/lib/barr/controller.rb @@ -1,27 +1,27 @@ module Barr class Controller - attr_accessor :file, :output, :retry_at, :interval, :id - - def initialize opts={} + attr_accessor :output, :retry_at, :interval, :id + attr_writer :file + + def initialize(opts = {}) @id = opts[:id] @interval = opts[:interval] || 5 @interval = (@interval * 10).round @output = {} end - def run! - end + def run!; end def update! @output = JSON.parse(`cat #{filename}`, symbolize_names: true) end def file - @file ||= File.new(filename, "w" ) + @file ||= File.new(filename, 'w') end def filename - @filename ||= "/tmp/barr-#{self.class.name}-#{@id}".gsub("::","-").downcase + @filename ||= "/tmp/barr-#{self.class.name}-#{@id}".gsub('::', '-').downcase end def close_file @@ -31,8 +31,7 @@ def close_file end def destroy! - close_file + close_file end - end end diff --git a/lib/barr/controllers/bbc_weather.rb b/lib/barr/controllers/bbc_weather.rb index dbf39b5..badf8f9 100644 --- a/lib/barr/controllers/bbc_weather.rb +++ b/lib/barr/controllers/bbc_weather.rb @@ -6,42 +6,39 @@ module Barr module Controllers class BBCWeather < Controller - - def initialize opts={} + def initialize(opts = {}) super - @temp_unit = (opts[:temp_unit] || "c").downcase - @speed_unit = (opts[:speed_unit] || "mph").downcase + @temp_unit = (opts[:temp_unit] || 'c').downcase + @speed_unit = (opts[:speed_unit] || 'mph').downcase end - + def run! - @thread = Thread.new do - loop do - begin + @thread = Thread.new do + loop do + begin url = "http://www.bbc.co.uk/weather/#{@id}" - + op = {} - + noko = Nokogiri::HTML(open(url)) op[:temperature] = noko.css("div.observationsRecord span.units-value.temperature-value.temperature-value-unit-#{@temp_unit}").text - op[:summary] = noko.css("div.observationsRecord p.weather-type img").attribute("alt").value + op[:summary] = noko.css('div.observationsRecord p.weather-type img').attribute('alt').value op[:windspeed] = noko.css("div.observationsRecord span.speed span.units-values.windspeed-units-values span.windspeed-value-unit-#{@speed_unit}").text - op[:winddirection] = noko.css("div.observationsRecord p.wind-speed span.wind.wind-speed").attribute("data-tooltip-mph").value.split(", ")[1] - op[:humidity] = noko.css("div.observationsRecord p.humidity span.data").text - op[:visibility] = noko.css("div.observationsRecord p.visibility span.data").text - op[:pressure] = noko.css("div.observationsRecord p.pressure span.data").text - + op[:winddirection] = noko.css('div.observationsRecord p.wind-speed span.wind.wind-speed').attribute('data-tooltip-mph').value.split(', ')[1] + op[:humidity] = noko.css('div.observationsRecord p.humidity span.data').text + op[:visibility] = noko.css('div.observationsRecord p.visibility span.data').text + op[:pressure] = noko.css('div.observationsRecord p.pressure span.data').text + File.write(filename, op.to_json) - + sleep 600 rescue StandardError => e - STDERR.puts "thread error!" + STDERR.puts 'thread error!' STDERR.puts e.message STDERR.puts e.backtrace end - end - end @thread.run end @@ -49,7 +46,6 @@ def run! def document(url) Nokogiri::HTML(open(url)) end - end end end diff --git a/lib/barr/controllers/http_grab.rb b/lib/barr/controllers/http_grab.rb index 3b1d554..35be0d1 100644 --- a/lib/barr/controllers/http_grab.rb +++ b/lib/barr/controllers/http_grab.rb @@ -10,7 +10,7 @@ module Controllers class HTTPGrab < Controller include Capybara::DSL - def initialize opts={} + def initialize(opts = {}) super @type = (opts[:type] || 'css').downcase.to_sym @selector = opts[:selector] @@ -19,23 +19,23 @@ def initialize opts={} def run! @thread = Thread.new do - loop do + loop do begin - grabbed = "" + grabbed = '' visit(@url) noko = Nokogiri::HTML(page.html) - + if @type == :css grabbed = noko.css(@selector).first.text elsif @type == :xpath grabbed = noko.xpath(@selector).first.text end - File.write(filename, {text: grabbed}.to_json) + File.write(filename, { text: grabbed }.to_json) sleep @interval rescue StandardError => e - STDERR.puts "HTTPGrab Controller Error" + STDERR.puts 'HTTPGrab Controller Error' STDERR.puts e.message STDERR.puts e.backtrace end diff --git a/lib/barr/controllers/playerctl.rb b/lib/barr/controllers/playerctl.rb index 629498e..44818e2 100644 --- a/lib/barr/controllers/playerctl.rb +++ b/lib/barr/controllers/playerctl.rb @@ -3,10 +3,9 @@ module Barr module Controllers class Playerctl < Controller - - def initialize opts={} + def initialize(opts = {}) super - @player = opts[:player] || "" + @player = opts[:player] || '' end def run! @@ -23,24 +22,22 @@ def run! sleep 5 rescue StandardError => e - STDERR.puts "thread error!" + STDERR.puts 'thread error!' STDERR.puts e.message STDERR.puts e.backtrace end - end end @thread.run end - def sys_cmd key + def sys_cmd(key) if !@player.empty? `playerctl -p #{@player} metadata #{key}` else `playerctl metadata #{key}` end end - end end end diff --git a/lib/barr/manager.rb b/lib/barr/manager.rb index e94da71..e3bf6a3 100644 --- a/lib/barr/manager.rb +++ b/lib/barr/manager.rb @@ -3,8 +3,7 @@ module Barr class Manager - - ERROR_ICON = "%{F#FF0000}\uf071%{F-}" + ERROR_ICON = "%{F#FF0000}\uf071%{F-}".freeze attr_reader :count, :blocks @@ -22,20 +21,20 @@ def add(block) def destroy! @blocks.each(&:destroy!) - @controllers.values.each(&:destroy!) + @controllers.each_value(&:destroy!) end - def controller type, opts={} - opts[:id] ||= "" + def controller(type, opts = {}) + opts[:id] ||= '' key = "#{type}_#{opts[:id]}" - + return @controllers[key] if @controllers[key] - - controller = Object.const_get("Barr::Controllers::"+type.to_s).new(opts) - @controllers[key]=controller + + controller = Object.const_get('Barr::Controllers::' + type.to_s).new(opts) + @controllers[key] = controller controller.run! - return controller + controller end def draw @@ -50,19 +49,19 @@ def draw right_blocks = outputs[:r].join '' bar_render = '' - bar_render << "%{l}#{left_blocks} " if left_blocks.length > 0 - bar_render << "%{c} #{centre_blocks} " if centre_blocks.length > 0 - bar_render << "%{r} #{right_blocks}" if right_blocks.length > 0 + bar_render << "%{l}#{left_blocks} " unless left_blocks.empty? + bar_render << "%{c} #{centre_blocks} " unless centre_blocks.empty? + bar_render << "%{r} #{right_blocks}" unless right_blocks.empty? - bar_render.gsub! "\n", '' + bar_render.delete! "\n" system('echo', '-e', bar_render.encode('UTF-8')) end def run! - while true - self.update! - self.draw + loop do + update! + draw sleep 0.1 end end @@ -70,9 +69,9 @@ def run! def update! @blocks.each do |block| begin - block.update! if @count == 0 || (@count % block.interval == 0) + block.update! if @count.zero? || (@count % block.interval).zero? rescue StandardError => e - STDERR.puts "block: " + e.class.name + STDERR.puts 'block: ' + e.class.name STDERR.puts e.message STDERR.puts e.backtrace block << ERROR_ICON unless block.output.include?(ERROR_ICON) @@ -80,11 +79,11 @@ def update! end end - @controllers.values.each do |controller| + @controllers.each_value do |controller| begin - controller.update! if @count == 1 || (@count % controller.interval == 0) + controller.update! if @count == 1 || (@count % controller.interval).zero? rescue StandardError => e - STDERR.puts "controller: " + e.class.name + STDERR.puts 'controller: ' + e.class.name STDERR.puts e.message STDERR.puts e.backtrace next @@ -97,15 +96,25 @@ def update! def id @id ||= SecureRandom.uuid end - + # compatibility methods. # alias_method would work here, but for consistency with Block # I'll define them this way - def update; update!; end - def run; run!; end - def destroy; destroy!; end - def add_block(block); add(block); end + def update + update! + end + + def run + run! + end + def destroy + destroy! + end + + def add_block(block) + add(block) + end end end diff --git a/lib/barr/version.rb b/lib/barr/version.rb index fbec57e..abea2a6 100644 --- a/lib/barr/version.rb +++ b/lib/barr/version.rb @@ -1,3 +1,3 @@ module Barr - VERSION = "0.3.0" + VERSION = '0.3.0'.freeze end diff --git a/spec/block_spec.rb b/spec/block_spec.rb index 854cb40..50b47aa 100644 --- a/spec/block_spec.rb +++ b/spec/block_spec.rb @@ -3,7 +3,6 @@ require 'barr/block' RSpec.describe Barr::Block do - describe '#initialize' do subject { described_class.new } @@ -32,7 +31,6 @@ expect(subject.interval).to eq 50 end end - end describe '#<<' do @@ -51,11 +49,11 @@ end it 'warns about deprecated options' do - opts = { bcolor: "#ccc", fcolor: "#bbb" } + opts = { bcolor: '#ccc', fcolor: '#bbb' } @old = described_class.new(opts) - - expect(@old.fgcolor).to eq("#bbb") - expect(@old.bgcolor).to eq("#ccc") + + expect(@old.fgcolor).to eq('#bbb') + expect(@old.bgcolor).to eq('#ccc') end end @@ -70,41 +68,39 @@ end describe 'aliased classes' do - it "should not raise errors" do - expect{[Barr::Blocks::Cpu, - Barr::Blocks::Hdd, - Barr::Blocks::Ip, - Barr::Blocks::WhoAmI - ]}.to_not raise_error + it 'should not raise errors' do + expect do + [Barr::Blocks::Cpu, + Barr::Blocks::Hdd, + Barr::Blocks::Ip, + Barr::Blocks::WhoAmI] end.to_not raise_error end end - - describe "tmp_filename" do - it "should return unique filename" do + describe 'tmp_filename' do + it 'should return unique filename' do expect(subject.tmp_filename).to match(/^\/tmp\/(\w|\W|block|\d)+$/i) end end - describe "format_string_from_hash" do - before { subject.format = "${VAR1} ${VAR2} ${VAR3}" } + describe 'format_string_from_hash' do + before { subject.format = '${VAR1} ${VAR2} ${VAR3}' } - it "substitutes the variables" do - opts = {var1: "test", var2: "another test", var3: "word"} - expect(subject.format_string_from_hash(opts)).to eq("test another test word") + it 'substitutes the variables' do + opts = { var1: 'test', var2: 'another test', var3: 'word' } + expect(subject.format_string_from_hash(opts)).to eq('test another test word') end - it "blanks missing variables" do - opts = {var1: "test"} + it 'blanks missing variables' do + opts = { var1: 'test' } - expect(subject.format_string_from_hash(opts)).to eq("test ") + expect(subject.format_string_from_hash(opts)).to eq('test ') end - it "is not case sensitive" do - opts = {var1: "test"} - subject.format = "${vAr1}" - expect(subject.format_string_from_hash(opts)).to eq("test") + it 'is not case sensitive' do + opts = { var1: 'test' } + subject.format = '${vAr1}' + expect(subject.format_string_from_hash(opts)).to eq('test') end - end end diff --git a/spec/blocks/battery_spec.rb b/spec/blocks/battery_spec.rb index bc424b3..3682bda 100644 --- a/spec/blocks/battery_spec.rb +++ b/spec/blocks/battery_spec.rb @@ -1,37 +1,34 @@ require 'barr/blocks/battery' RSpec.describe Barr::Blocks::Battery do - - describe "#initialize" do - - it "sets default show_remaining" do + describe '#initialize' do + it 'sets default show_remaining' do expect(subject.show_remaining).to be(true) end - end - describe "#update" do - let(:battery_remaining) { "96%, 03:17:39 remaining" } - let(:battery_no_remaining) { "96%" } - + describe '#update' do + let(:battery_remaining) { '96%, 03:17:39 remaining' } + let(:battery_no_remaining) { '96%' } + before do @remaining = described_class.new show_remaining: true @no_remaining = described_class.new show_remaining: false allow(@remaining).to receive(:battery_remaining).and_return(battery_remaining) - allow(@no_remaining).to receive(:battery_no_remaining).and_return(battery_no_remaining) + allow(@no_remaining).to receive(:battery_no_remaining).and_return(battery_no_remaining) end - it "renders remaining output correctly" do + it 'renders remaining output correctly' do @remaining.update - - expect(@remaining.output).to eq("96%, 03:17:39 remaining") + + expect(@remaining.output).to eq('96%, 03:17:39 remaining') end - it "render no remaining output correctly" do + it 'render no remaining output correctly' do @no_remaining.update - expect(@no_remaining.output).to eq("96%") + expect(@no_remaining.output).to eq('96%') end end end diff --git a/spec/blocks/bbc_weather_spec.rb b/spec/blocks/bbc_weather_spec.rb index 25ad7a8..070bad4 100644 --- a/spec/blocks/bbc_weather_spec.rb +++ b/spec/blocks/bbc_weather_spec.rb @@ -2,28 +2,26 @@ require './spec/mocks/bbc_weather' RSpec.describe Barr::Blocks::BBCWeatherBlockMock do - describe '#initialize' do - it "sets default format" do - expect(subject.format).to eq("${TEMPERATURE} - ${SUMMARY}") + it 'sets default format' do + expect(subject.format).to eq('${TEMPERATURE} - ${SUMMARY}') end end describe 'config' do - it "sets the controller" do + it 'sets the controller' do subject.config expect(subject.controller).to be_a(Barr::Controllers::BBCWeatherControllerMock) end end describe 'update' do - it "sets the output correctly" do - subject.location = "123456" + it 'sets the output correctly' do + subject.location = '123456' subject.config subject.controller.update! subject.update! - expect(subject.output).to eq("%{A:barr_open_url http www.bbc.co.uk/weather/123456:}17 C - Nice outside%{A}") + expect(subject.output).to eq('%{A:barr_open_url http www.bbc.co.uk/weather/123456:}17 C - Nice outside%{A}') end end - end diff --git a/spec/blocks/bspwm_spec.rb b/spec/blocks/bspwm_spec.rb index 04b2b86..f5fbd24 100644 --- a/spec/blocks/bspwm_spec.rb +++ b/spec/blocks/bspwm_spec.rb @@ -2,72 +2,68 @@ require './spec/mocks/bspwm' RSpec.describe Barr::Blocks::Bspwm do - before do - allow_any_instance_of(described_class).to receive(:sys_cmd).and_return($bsp_json) + allow_any_instance_of(described_class).to receive(:sys_cmd).and_return($bsp_json) # rubocop:disable Style/GlobalVars end describe '#initialize' do it 'sets default focus_markers' do - expect(subject.focus_markers).to eq(%w(> <)) + expect(subject.focus_markers).to eq(%w[> <]) end it 'sets default focus inversion' do expect(subject.invert_focus_colors).to be(false) end - it "sets default monitor" do - expect(subject.monitor).to eq(2097153) + it 'sets default monitor' do + expect(subject.monitor).to eq(2_097_153) end - end describe '#bsp_tree' do before { subject.bsp_tree } - it "has monitors" do - expect(subject.tree["monitors"].count).to eq(1) - end - - it "desktops" do - expect(subject.tree["monitors"].first["desktops"].count).to eq(6) - expect(subject.tree["monitors"].first["desktops"].first["name"]).to eq("web") + it 'has monitors' do + expect(subject.tree['monitors'].count).to eq(1) end + it 'desktops' do + expect(subject.tree['monitors'].first['desktops'].count).to eq(6) + expect(subject.tree['monitors'].first['desktops'].first['name']).to eq('web') + end end describe 'update!' do before { subject.update! } - it "renders output correctly" do - expect(subject.output).to eq("> web < %{A:bspc desktop -f 2097156:} media %{A} %{A:bspc desktop -f 2097157:} web %{A} %{A:bspc desktop -f 2097158:} shell %{A} %{A:bspc desktop -f 2097159:} steam %{A} %{A:bspc desktop -f 2097160:} sys %{A}") + it 'renders output correctly' do + expect(subject.output).to eq('> web < %{A:bspc desktop -f 2097156:} media %{A} %{A:bspc desktop -f 2097157:} web %{A} %{A:bspc desktop -f 2097158:} shell %{A} %{A:bspc desktop -f 2097159:} steam %{A} %{A:bspc desktop -f 2097160:} sys %{A}') end end - - describe "desktops" do + describe 'desktops' do before do subject.invert_focus_colors = true subject.update! - @fd = subject.tree["monitors"].first["desktops"].first - @ud = subject.tree["monitors"].first["desktops"].last + @fd = subject.tree['monitors'].first['desktops'].first + @ud = subject.tree['monitors'].first['desktops'].last end after { subject.invert_focus_colors = false } - - describe "#focused_desktop" do + + describe '#focused_desktop' do before { @op = subject.focused_desktop(@fd) } - it "renders in the correct format" do - expect(@op).to eq("%{R}> web <%{R}") + it 'renders in the correct format' do + expect(@op).to eq('%{R}> web <%{R}') end end - describe "#unfocused_desktop" do + describe '#unfocused_desktop' do before { @op = subject.unfocused_desktop(@ud) } - it "renders in the correct format" do - expect(@op).to eq("%{A:bspc desktop -f 2097160:} sys %{A}") + it 'renders in the correct format' do + expect(@op).to eq('%{A:bspc desktop -f 2097160:} sys %{A}') end end end diff --git a/spec/blocks/clock_spec.rb b/spec/blocks/clock_spec.rb index 009a4a2..a4fd90d 100644 --- a/spec/blocks/clock_spec.rb +++ b/spec/blocks/clock_spec.rb @@ -1,7 +1,6 @@ require 'barr/blocks/clock' RSpec.describe Barr::Blocks::Clock do - describe '#update!' do before do time = Time.local(2016, 3, 17, 20, 0, 0) @@ -16,5 +15,4 @@ expect(subject.output).to eq '20:00 17 Mar 2016' end end - end diff --git a/spec/blocks/conky_spec.rb b/spec/blocks/conky_spec.rb index 4e9d0f1..bba0274 100644 --- a/spec/blocks/conky_spec.rb +++ b/spec/blocks/conky_spec.rb @@ -1,32 +1,28 @@ require 'barr/blocks/conky' - - RSpec.describe Barr::Blocks::Conky do before do allow_any_instance_of(described_class).to receive(:spawn_conky).and_return(true) allow_any_instance_of(described_class).to receive(:write_template).and_return(true) - allow_any_instance_of(described_class).to receive(:sys_cmd).and_return("0.2 0.2") - + allow_any_instance_of(described_class).to receive(:sys_cmd).and_return('0.2 0.2') end - describe "initialize" do - it "accepts text option" do - expect(described_class.new(text: "${cpu}").text).to eq("${cpu}") + describe 'initialize' do + it 'accepts text option' do + expect(described_class.new(text: '${cpu}').text).to eq('${cpu}') end - it "spawns the conky" do + it 'spawns the conky' do expect(described_class.new).to have_received(:spawn_conky).once expect(described_class.new).to have_received(:write_template).once end end - describe "update" do - it "renders the correct format" do + describe 'update' do + it 'renders the correct format' do subject.update - expect(subject.output).to eq("0.2 0.2") + expect(subject.output).to eq('0.2 0.2') end end - end diff --git a/spec/blocks/cpu_spec.rb b/spec/blocks/cpu_spec.rb index 0c66d26..4cb5d40 100644 --- a/spec/blocks/cpu_spec.rb +++ b/spec/blocks/cpu_spec.rb @@ -1,8 +1,7 @@ -# coding: utf-8 + require 'barr/blocks/cpu' RSpec.describe Barr::Blocks::CPU do - describe '#update!' do let(:load_sys_cmd) { '6.7744' } let(:temp_sys_cmd) { '28500' } @@ -24,5 +23,4 @@ expect(subject.output).to eq '28.5°' end end - end diff --git a/spec/blocks/hdd_spec.rb b/spec/blocks/hdd_spec.rb index c1feed4..fe62eb6 100644 --- a/spec/blocks/hdd_spec.rb +++ b/spec/blocks/hdd_spec.rb @@ -1,7 +1,6 @@ require 'barr/blocks/hdd' RSpec.describe Barr::Blocks::HDD do - describe '#update!' do subject { described_class.new device: 'sdc2' } @@ -16,5 +15,4 @@ expect(subject.output).to eq '34G / 213G (17%)' end end - end diff --git a/spec/blocks/http_grab_spec.rb b/spec/blocks/http_grab_spec.rb index 5e17663..873247b 100644 --- a/spec/blocks/http_grab_spec.rb +++ b/spec/blocks/http_grab_spec.rb @@ -2,30 +2,28 @@ require './spec/mocks/http_grab' RSpec.describe Barr::Blocks::HTTPGrabBlockMock do - describe '#initialize' do - it "sets defaults" do + it 'sets defaults' do expect(subject.link).to be_falsey expect(subject.type).to eq(:css) end end describe 'config' do - it "sets the controller" do + it 'sets the controller' do subject.config expect(subject.controller).to be_a(Barr::Controllers::HTTPGrabControllerMock) end end describe 'update' do - it "sets the output correctly" do - subject.url = "http://fakedomain.com/url" + it 'sets the output correctly' do + subject.url = 'http://fakedomain.com/url' subject.link = true subject.config subject.controller.update! subject.update! - expect(subject.output).to eq("%{A:barr_open_url http fakedomain.com/url:}Top news article!%{A}") + expect(subject.output).to eq('%{A:barr_open_url http fakedomain.com/url:}Top news article!%{A}') end end - end diff --git a/spec/blocks/hue_group_spec.rb b/spec/blocks/hue_group_spec.rb index e6a14b2..a81695c 100644 --- a/spec/blocks/hue_group_spec.rb +++ b/spec/blocks/hue_group_spec.rb @@ -1,14 +1,13 @@ -# coding: utf-8 + require 'barr/blocks/hue_group' RSpec.describe Barr::Blocks::HueGroup do - describe '#update!' do before do subject.id = 5 end - describe "the output" do + describe 'the output' do it 'sets the default off button correctly' do subject.format = '${OFF}' subject.update! @@ -21,43 +20,41 @@ expect(subject.output).to eq '%{A:hue group 5 on:}[on]%{A}' end - it "sets custom text correctly" do + it 'sets custom text correctly' do subject.format = '${OFF:T-custom off}' subject.update! expect(subject.output).to eq '%{A:hue group 5 off:}[custom off]%{A}' end - it "sets hue correctly" do + it 'sets hue correctly' do subject.format = '${ON:H-1500}' subject.update! expect(subject.output).to eq '%{A:hue group 5 --hue 1500:}[on]%{A}' end - it "sets alerts correctly" do + it 'sets alerts correctly' do subject.format = '${ON:A-lselect}' subject.update! expect(subject.output).to eq '%{A:hue group 5 --alert lselect:}[on]%{A}' end - it "sets brightness correctly" do + it 'sets brightness correctly' do subject.format = '${ON:B-25}' subject.update! expect(subject.output).to eq '%{A:hue group 5 --brightness 25:}[on]%{A}' end - it "sets multiple options correctly" do - subject.format = "${ON:B-200,T-Quite Bright,H-65000}" + it 'sets multiple options correctly' do + subject.format = '${ON:B-200,T-Quite Bright,H-65000}' subject.update! expect(subject.output).to eq '%{A:hue group 5 --brightness 200 --hue 65000:}[Quite Bright]%{A}' end - it "sets multiple buttons correctly" do - subject.format = "${OFF:T-turn off} ${ON}" + it 'sets multiple buttons correctly' do + subject.format = '${OFF:T-turn off} ${ON}' subject.update! - expect(subject.output).to eq("%{A:hue group 5 off:}[turn off]%{A} %{A:hue group 5 on:}[on]%{A}") + expect(subject.output).to eq('%{A:hue group 5 off:}[turn off]%{A} %{A:hue group 5 on:}[on]%{A}') end - end end - end diff --git a/spec/blocks/hue_light_spec.rb b/spec/blocks/hue_light_spec.rb index 048b114..80b92bd 100644 --- a/spec/blocks/hue_light_spec.rb +++ b/spec/blocks/hue_light_spec.rb @@ -1,14 +1,13 @@ -# coding: utf-8 + require 'barr/blocks/hue_light' RSpec.describe Barr::Blocks::HueLight do - describe '#update!' do before do subject.id = 5 end - describe "the output" do + describe 'the output' do it 'sets the default off button correctly' do subject.format = '${OFF}' subject.update! @@ -21,43 +20,41 @@ expect(subject.output).to eq '%{A:hue light 5 on:}[on]%{A}' end - it "sets custom text correctly" do + it 'sets custom text correctly' do subject.format = '${OFF:T-custom off}' subject.update! expect(subject.output).to eq '%{A:hue light 5 off:}[custom off]%{A}' end - it "sets hue correctly" do + it 'sets hue correctly' do subject.format = '${ON:H-1500}' subject.update! expect(subject.output).to eq '%{A:hue light 5 --hue 1500:}[on]%{A}' end - it "sets alerts correctly" do + it 'sets alerts correctly' do subject.format = '${ON:A-lselect}' subject.update! expect(subject.output).to eq '%{A:hue light 5 --alert lselect:}[on]%{A}' end - it "sets brightness correctly" do + it 'sets brightness correctly' do subject.format = '${ON:B-25}' subject.update! expect(subject.output).to eq '%{A:hue light 5 --brightness 25:}[on]%{A}' end - it "sets multiple options correctly" do - subject.format = "${ON:B-200,T-Quite Bright,H-65000}" + it 'sets multiple options correctly' do + subject.format = '${ON:B-200,T-Quite Bright,H-65000}' subject.update! expect(subject.output).to eq '%{A:hue light 5 --brightness 200 --hue 65000:}[Quite Bright]%{A}' end - it "sets multiple buttons correctly" do - subject.format = "${OFF:T-turn off} ${ON}" + it 'sets multiple buttons correctly' do + subject.format = '${OFF:T-turn off} ${ON}' subject.update! - expect(subject.output).to eq("%{A:hue light 5 off:}[turn off]%{A} %{A:hue light 5 on:}[on]%{A}") + expect(subject.output).to eq('%{A:hue light 5 off:}[turn off]%{A} %{A:hue light 5 on:}[on]%{A}') end - end end - end diff --git a/spec/blocks/i3_spec.rb b/spec/blocks/i3_spec.rb index 35197ef..8dd61ed 100644 --- a/spec/blocks/i3_spec.rb +++ b/spec/blocks/i3_spec.rb @@ -2,20 +2,18 @@ require './spec/mocks/i3' RSpec.describe Barr::Blocks::I3 do - before do allow_any_instance_of(described_class).to receive(:i3_connection).and_return(I3IpcMock.new) end describe '#initialize' do it 'sets default focus_markers' do - expect(subject.focus_markers).to eq %w(> <) + expect(subject.focus_markers).to eq %w[> <] end it 'sets an i3 connection' do expect(subject.i3).to be_a I3IpcMock end - end describe '#update!' do @@ -37,5 +35,4 @@ expect(a.output).to eq '%{A:barr_i3ipc "workspace a":} a %{A}%{A:barr_i3ipc "workspace 2\: b":} 2: b %{A}%{R}>c<%{R}' end end - end diff --git a/spec/blocks/ip_spec.rb b/spec/blocks/ip_spec.rb index ed7cb52..f4ab24c 100644 --- a/spec/blocks/ip_spec.rb +++ b/spec/blocks/ip_spec.rb @@ -1,7 +1,6 @@ require 'barr/blocks/ip' RSpec.describe Barr::Blocks::IP do - describe '#initialize' do it 'sets a default device' do expect(subject.device).to eq 'lo' @@ -39,5 +38,4 @@ end end end - end diff --git a/spec/blocks/mem_spec.rb b/spec/blocks/mem_spec.rb index 2ae4590..99fe082 100644 --- a/spec/blocks/mem_spec.rb +++ b/spec/blocks/mem_spec.rb @@ -1,7 +1,6 @@ require 'barr/blocks/mem' RSpec.describe Barr::Blocks::Mem do - describe '#update!' do let(:sys_cmd) { '6.0G / 15.6G' } @@ -14,5 +13,4 @@ expect(subject.output).to eq '6.0G / 15.6G' end end - end diff --git a/spec/blocks/mpd_spec.rb b/spec/blocks/mpd_spec.rb index cc849d8..ac855e5 100644 --- a/spec/blocks/mpd_spec.rb +++ b/spec/blocks/mpd_spec.rb @@ -1,8 +1,7 @@ -# coding: utf-8 + require 'barr/blocks/mpd' RSpec.describe Barr::Blocks::MPD do - let(:sys_cmd) { 'Muse - Knights Of Cydonia' } before do diff --git a/spec/blocks/playerctl_spec.rb b/spec/blocks/playerctl_spec.rb index fa3656f..88b1477 100644 --- a/spec/blocks/playerctl_spec.rb +++ b/spec/blocks/playerctl_spec.rb @@ -2,28 +2,26 @@ require './spec/mocks/playerctl' RSpec.describe Barr::Blocks::PlayerctlBlockMock do - describe '#initialize' do - it "sets default format" do - expect(subject.format).to eq("${ARTIST} - ${TITLE}") + it 'sets default format' do + expect(subject.format).to eq('${ARTIST} - ${TITLE}') end end describe 'config' do - it "sets the controller" do + it 'sets the controller' do subject.config expect(subject.controller).to be_a(Barr::Controllers::PlayerctlControllerMock) end end describe 'update' do - it "sets the output correctly" do - subject.format = "${ARTIST} - ${ALBUM} - ${NEXT}" + it 'sets the output correctly' do + subject.format = '${ARTIST} - ${ALBUM} - ${NEXT}' subject.config subject.controller.update! subject.update! expect(subject.output).to eq("Slayer - Reign in Blood - %{A:playerctl next:}\uf051%{A}") end end - end diff --git a/spec/blocks/processes_spec.rb b/spec/blocks/processes_spec.rb index 0019505..c247856 100644 --- a/spec/blocks/processes_spec.rb +++ b/spec/blocks/processes_spec.rb @@ -1,12 +1,12 @@ require 'barr/blocks/processes' RSpec.describe Barr::Blocks::Processes do - let(:sys_cmd) { "468" } + let(:sys_cmd) { '468' } before { allow(subject).to receive(:sys_cmd).and_return(sys_cmd) } - - it "sets number of active processes" do - subject.update - expect(subject.output).to eq("468") + + it 'sets number of active processes' do + subject.update + expect(subject.output).to eq('468') end end diff --git a/spec/blocks/rhythmbox_spec.rb b/spec/blocks/rhythmbox_spec.rb index bc905fe..9fd4a42 100644 --- a/spec/blocks/rhythmbox_spec.rb +++ b/spec/blocks/rhythmbox_spec.rb @@ -1,8 +1,7 @@ -# coding: utf-8 + require 'barr/blocks/rhythmbox' RSpec.describe Barr::Blocks::Rhythmbox do - let(:sys_cmd) { 'Marilyn Manson - Into The Fire' } before do diff --git a/spec/blocks/separator_spec.rb b/spec/blocks/separator_spec.rb index 5f4bb91..ac8e664 100644 --- a/spec/blocks/separator_spec.rb +++ b/spec/blocks/separator_spec.rb @@ -1,7 +1,6 @@ require 'barr/blocks/separator' RSpec.describe Barr::Blocks::Separator do - describe '#update!' do before { subject.update! } @@ -9,5 +8,4 @@ expect(subject.output).to eq '|' end end - end diff --git a/spec/blocks/temperature_spec.rb b/spec/blocks/temperature_spec.rb index 23541a1..7047d7f 100644 --- a/spec/blocks/temperature_spec.rb +++ b/spec/blocks/temperature_spec.rb @@ -1,9 +1,8 @@ -# coding: utf-8 + require 'barr/blocks/temperature' require './spec/mocks/weather' RSpec.describe Barr::Blocks::Temperature do - describe '#update!' do subject { described_class.new location: '12723' } @@ -16,5 +15,4 @@ expect(subject.output).to eq "%{A:xdg-open 'https\:\/\/weather.yahoo.com/country/state/city-12723/':}100°C Nice day%{A}" end end - end diff --git a/spec/blocks/whoami_spec.rb b/spec/blocks/whoami_spec.rb index bfd9760..6804e8b 100644 --- a/spec/blocks/whoami_spec.rb +++ b/spec/blocks/whoami_spec.rb @@ -1,7 +1,6 @@ require 'barr/blocks/whoami' RSpec.describe Barr::Blocks::Whoami do - before do allow(subject).to receive(:sys_cmd).and_return('dave') end @@ -13,5 +12,4 @@ expect(subject.output).to eq('dave') end end - end diff --git a/spec/manager_spec.rb b/spec/manager_spec.rb index 8c9b9c6..6122f1c 100644 --- a/spec/manager_spec.rb +++ b/spec/manager_spec.rb @@ -1,7 +1,6 @@ require 'barr/manager' RSpec.describe Barr::Manager do - let(:block1) { Barr::Block.new interval: 1 } let(:block2) { Barr::Block.new interval: 5 } @@ -50,5 +49,4 @@ subject.destroy! end end - end diff --git a/spec/mocks/bbc_weather.rb b/spec/mocks/bbc_weather.rb index c5974b9..88fc343 100644 --- a/spec/mocks/bbc_weather.rb +++ b/spec/mocks/bbc_weather.rb @@ -1,4 +1,4 @@ -# coding: utf-8 + require 'barr/block' require 'barr/controller' require 'barr/blocks/bbc_weather' @@ -8,32 +8,25 @@ module Barr module Controllers class BBCWeatherControllerMock < Barr::Controllers::BBCWeather - - def document - end - - def run! - end - + def document; end + + def run!; end + def update! @output ||= {} - @output[:temperature] = "17 C" - @output[:summary] = "Nice outside" - @output[:windspeed] = "5 mp/h" + @output[:temperature] = '17 C' + @output[:summary] = 'Nice outside' + @output[:windspeed] = '5 mp/h' end - end end - module Blocks class BBCWeatherBlockMock < Barr::Blocks::BBCWeather def config - opts = {id: @location} + opts = { id: @location } @controller = Barr::Controllers::BBCWeatherControllerMock.new opts end end end end - - diff --git a/spec/mocks/bspwm.rb b/spec/mocks/bspwm.rb index df538b6..24be215 100644 --- a/spec/mocks/bspwm.rb +++ b/spec/mocks/bspwm.rb @@ -1,4 +1,4 @@ -$bsp_json = < Date: Sat, 3 Mar 2018 23:03:00 +0000 Subject: [PATCH 13/21] Fix/update examples --- examples/all_in.rb | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/examples/all_in.rb b/examples/all_in.rb index 671eefb..4d59686 100755 --- a/examples/all_in.rb +++ b/examples/all_in.rb @@ -9,23 +9,18 @@ i3 = Barr::Blocks::I3.new(fgcolor: '#FFF', bgcolor: '#145266', - focus_markers: %w[> <], + focus_markers: [' ', ' '], + invert_focus_colors: true, align: :r, icon: "\uf009", - interval: 0.2) + interval: 0.1) -artist = Barr::Blocks::Rhythmbox.new(bgcolor: '#466B41', - icon: "\uf028", - title: false, - buttons: false) +music = Barr::Blocks::Playerctl.new(bgcolor: '#1E6614', + format: "${ARTIST} - ${TITLE}", + interval: 2) -song = Barr::Blocks::Rhythmbox.new(bgcolor: '#1E6614', - buttons: false, - artist: false) - -controls = Barr::Blocks::Rhythmbox.new(bgcolor: '#0A4D02', - artist: false, - title: false, +controls = Barr::Blocks::Playerctl.new(bgcolor: '#0A4D02', + format: "${BUTTONS}", align: :r) clock = Barr::Blocks::Clock.new(bgcolor: '#371E5E', @@ -33,11 +28,11 @@ icon: "\uf073", align: :r) -weather = Barr::Blocks::Temperature.new(bgcolor: '#4A072B', - align: :l, - location: '2471217', - icon: "\uf0c2 Philadelphia: ", - interval: 1500) +weather = Barr::Blocks::BBCWeather.new(bgcolor: '#4A072B', + align: :l, + location: 'b17', + icon: "\uf0c2 Birmingham: ", + interval: 1500) cpu = Barr::Blocks::CPU.new icon: "\uf1fe", format: '${LOAD}% ${TEMP}' @@ -47,15 +42,14 @@ local = Barr::Blocks::IP.new bgcolor: '#937739', align: :r, icon: "\uf1ce" -office_lights = Barr::Blocks::HueGroup.new id: '3', +office_lights = Barr::Blocks::HueGroup.new id: '12', icon: "\uf1ad", format: '${OFF} ${ON:H-1,H-65535,B-255} ${ON:B-120,T-dim}', align: :r, bgcolor: '#0c1e3a', - fcolor: '#EEEEEE' + fgcolor: '#EEEEEE' # Left -@man.add artist -@man.add song +@man.add music @man.add weather @man.add cpu @man.add mem From cf125b0f988f999bee122fc9ebba2acdad9438d9 Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Sat, 3 Mar 2018 23:45:59 +0000 Subject: [PATCH 14/21] Fix BBCWeather Block to account for changes on BBC weather site --- examples/two_temperatures.rb | 25 ++++++++++++++----------- lib/barr/blocks/bbc_weather.rb | 2 +- lib/barr/controllers/bbc_weather.rb | 18 ++++++++++-------- spec/blocks/bbc_weather_spec.rb | 2 +- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/examples/two_temperatures.rb b/examples/two_temperatures.rb index 970bf09..b5a81a8 100755 --- a/examples/two_temperatures.rb +++ b/examples/two_temperatures.rb @@ -5,18 +5,21 @@ @man = Barr::Manager.new -nyc = Barr::Blocks::Temperature.new bgcolor: '#42C7AA', - fgcolor: '#FFF', - icon: 'New York: ', - location: '2459115', - interval: 1800 +nyc = Barr::Blocks::BBCWeather.new bgcolor: '#42C7AA', + fgcolor: '#FFF', + icon: 'New York: ', + location: '5128581', + interval: 15 -sanfran = Barr::Blocks::Temperature.new bgcolor: '#92A084', - fgcolor: '#FFF', - icon: 'San Francisco: ', - location: '2487956', - align: :r, - interval: 1800 +sanfran = Barr::Blocks::BBCWeather.new bgcolor: '#92A084', + fgcolor: '#FFF', + icon: 'San Francisco: ', + location: '5391959', + format: '${TEMPERATURE - ${SUMMARY} - ${WINDSPEED} - ${WINDDIRECTION}', + speed_unit: 'kph', + temp_unit: 'f', + align: :r, + interval: 30 @man.add nyc @man.add sanfran diff --git a/lib/barr/blocks/bbc_weather.rb b/lib/barr/blocks/bbc_weather.rb index 21affa8..9581f50 100644 --- a/lib/barr/blocks/bbc_weather.rb +++ b/lib/barr/blocks/bbc_weather.rb @@ -18,7 +18,7 @@ def config def update! op = @controller.output - @output = "%{A:barr_open_url http www.bbc.co.uk\/weather\/#{@location}:}#{format_string_from_hash(op)}%{A}" + @output = "%{A:barr_open_url https www.bbc.co.uk\/weather\/#{@location}:}#{format_string_from_hash(op)}%{A}" end end end diff --git a/lib/barr/controllers/bbc_weather.rb b/lib/barr/controllers/bbc_weather.rb index badf8f9..21cabd2 100644 --- a/lib/barr/controllers/bbc_weather.rb +++ b/lib/barr/controllers/bbc_weather.rb @@ -16,19 +16,21 @@ def run! @thread = Thread.new do loop do begin - url = "http://www.bbc.co.uk/weather/#{@id}" + url = "https://www.bbc.co.uk/weather/0/#{@id}" op = {} noko = Nokogiri::HTML(open(url)) - op[:temperature] = noko.css("div.observationsRecord span.units-value.temperature-value.temperature-value-unit-#{@temp_unit}").text - op[:summary] = noko.css('div.observationsRecord p.weather-type img').attribute('alt').value - op[:windspeed] = noko.css("div.observationsRecord span.speed span.units-values.windspeed-units-values span.windspeed-value-unit-#{@speed_unit}").text - op[:winddirection] = noko.css('div.observationsRecord p.wind-speed span.wind.wind-speed').attribute('data-tooltip-mph').value.split(', ')[1] - op[:humidity] = noko.css('div.observationsRecord p.humidity span.data').text - op[:visibility] = noko.css('div.observationsRecord p.visibility span.data').text - op[:pressure] = noko.css('div.observationsRecord p.pressure span.data').text + op[:temperature] = noko.css("div.wr-value--temperature .wr-value--temperature--#{@temp_unit} .wr-hide-visually").text + op[:summary] = noko.css('.wr-day__weather-type-description-container')[0].text + op[:windspeed] = noko.css("span.wr-wind-speed__icon span[data-unit=#{@speed_unit}]")[0].text + op[:winddirection] = noko.css('span.wind-rose__direction-abbr')[0].text.delete(' ') + + hvp = noko.css('li.wr-c-station-data__observation') + op[:humidity] = hvp[0].text + op[:visibility] = hvp[1].text + op[:pressure] = hvp[2].text File.write(filename, op.to_json) diff --git a/spec/blocks/bbc_weather_spec.rb b/spec/blocks/bbc_weather_spec.rb index 070bad4..55f18df 100644 --- a/spec/blocks/bbc_weather_spec.rb +++ b/spec/blocks/bbc_weather_spec.rb @@ -21,7 +21,7 @@ subject.config subject.controller.update! subject.update! - expect(subject.output).to eq('%{A:barr_open_url http www.bbc.co.uk/weather/123456:}17 C - Nice outside%{A}') + expect(subject.output).to eq('%{A:barr_open_url https www.bbc.co.uk/weather/123456:}17 C - Nice outside%{A}') end end end From 5a0c47662adc4951261445a2f89c1652a27ca5d0 Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Sun, 4 Mar 2018 00:02:49 +0000 Subject: [PATCH 15/21] Remove rhythmbox client example --- examples/README.md | 4 ---- examples/all_in.rb | 8 ++++---- examples/rhythm.rb | 18 ------------------ 3 files changed, 4 insertions(+), 26 deletions(-) delete mode 100755 examples/rhythm.rb diff --git a/examples/README.md b/examples/README.md index ecec740..adda4a5 100644 --- a/examples/README.md +++ b/examples/README.md @@ -20,10 +20,6 @@ ![i3_cpu_mem.rb](http://i.imgur.com/J3qNpw5.png) -## rhythm.rb - -![rhythm.rb](http://i.imgur.com/1P05aih.png) - ## time_and_date.rb ![time_and_date.rb](http://i.imgur.com/Lg81tSG.png) diff --git a/examples/all_in.rb b/examples/all_in.rb index 4d59686..71c1221 100755 --- a/examples/all_in.rb +++ b/examples/all_in.rb @@ -16,11 +16,11 @@ interval: 0.1) music = Barr::Blocks::Playerctl.new(bgcolor: '#1E6614', - format: "${ARTIST} - ${TITLE}", + format: '${ARTIST} - ${TITLE}', interval: 2) controls = Barr::Blocks::Playerctl.new(bgcolor: '#0A4D02', - format: "${BUTTONS}", + format: '${BUTTONS}', align: :r) clock = Barr::Blocks::Clock.new(bgcolor: '#371E5E', @@ -32,7 +32,7 @@ align: :l, location: 'b17', icon: "\uf0c2 Birmingham: ", - interval: 1500) + interval: 60) cpu = Barr::Blocks::CPU.new icon: "\uf1fe", format: '${LOAD}% ${TEMP}' @@ -42,7 +42,7 @@ local = Barr::Blocks::IP.new bgcolor: '#937739', align: :r, icon: "\uf1ce" -office_lights = Barr::Blocks::HueGroup.new id: '12', +office_lights = Barr::Blocks::HueGroup.new id: '3', icon: "\uf1ad", format: '${OFF} ${ON:H-1,H-65535,B-255} ${ON:B-120,T-dim}', align: :r, diff --git a/examples/rhythm.rb b/examples/rhythm.rb deleted file mode 100755 index 200c47a..0000000 --- a/examples/rhythm.rb +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env ruby - -require 'rubygems' -require 'barr' - -@man = Barr::Manager.new - -artist = Barr::Blocks::Rhythmbox.new align: :l, title: false, buttons: false, bgcolor: '#266623', icon: "\uf028" - -title = Barr::Blocks::Rhythmbox.new align: :l, artist: false, buttons: false, bgcolor: '#0D450A' - -btns = Barr::Blocks::Rhythmbox.new align: :r, artist: false, title: false, bgcolor: '#033B00', interval: 10_000 - -@man.add artist -@man.add title -@man.add btns - -@man.run! From 7b92377e8817cb36e6107e948c6ee97b091a615c Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Sun, 4 Mar 2018 00:09:53 +0000 Subject: [PATCH 16/21] Build against multiple ruby versions and force rubocop checks --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9d4e902..0f90ede 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,9 @@ language: ruby rvm: - 2.2.3 + - 2.4.0 + - 2.5.0 before_install: gem install bundler -v 1.11.2 +script: + - bundle exec rubocop + - bundle exec rspec spec From 2ca2aca10d75b77ba0be2b549db77fb75c8b882e Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Sun, 4 Mar 2018 00:45:46 +0000 Subject: [PATCH 17/21] Tweak CPU block usage percentage --- README.md | 2 +- barr.gemspec | 1 + examples/all_in.rb | 2 +- lib/barr/blocks/cpu.rb | 5 +++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0175958..e974eb0 100644 --- a/README.md +++ b/README.md @@ -218,7 +218,7 @@ Shows the current date and/or time. #### CPU -Shows CPU load averaged across all cores. +**Requires mpstat from [sysstat](https://github.com/sysstat/sysstat)**. Shows CPU load averaged across all cores. `cpu = Barr::Blocks::CPU.new` diff --git a/barr.gemspec b/barr.gemspec index 0956a95..71ad2d8 100644 --- a/barr.gemspec +++ b/barr.gemspec @@ -44,4 +44,5 @@ Gem::Specification.new do |spec| spec.requirements << '(Optional) RhythmBox & rhythmbox-client' spec.requirements << '(Optional) FontAwesome font' spec.requirements << '(Optional) playerctl' + spec.requirements << '(Optional) mpstat from sysstat' end diff --git a/examples/all_in.rb b/examples/all_in.rb index 71c1221..bb42bee 100755 --- a/examples/all_in.rb +++ b/examples/all_in.rb @@ -34,7 +34,7 @@ icon: "\uf0c2 Birmingham: ", interval: 60) -cpu = Barr::Blocks::CPU.new icon: "\uf1fe", format: '${LOAD}% ${TEMP}' +cpu = Barr::Blocks::CPU.new icon: "\uf1fe", format: '${LOAD} ${TEMP}' mem = Barr::Blocks::Mem.new bgcolor: '#333333' diff --git a/lib/barr/blocks/cpu.rb b/lib/barr/blocks/cpu.rb index 804047e..2769309 100644 --- a/lib/barr/blocks/cpu.rb +++ b/lib/barr/blocks/cpu.rb @@ -20,11 +20,12 @@ def update! private def load_sys_cmd - `grep 'cpu ' /proc/stat | awk -v RS="" '{print ($13-$2+$15-$4)*100/($13-$2+$15-$4+$16-$5)}'` + # courtesy of https://stackoverflow.com/a/9229907 + `mpstat | awk '$12 ~ /[0-9.]+/ { print 100 - $12"%" }'` end def temp_sys_cmd - `cat /sys/class/thermal/thermal_zone0/temp` + `cat /sys/class/thermal/thermal_zone0/temp`.chomp end end From 10738b8c062d53d05ca9b3c17ddd6d3469a8a038 Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Sun, 4 Mar 2018 00:53:45 +0000 Subject: [PATCH 18/21] Fix time_and_date.rb date example. Issue #45 --- examples/time_and_date.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/time_and_date.rb b/examples/time_and_date.rb index 4e4758e..a0de1c0 100755 --- a/examples/time_and_date.rb +++ b/examples/time_and_date.rb @@ -6,7 +6,7 @@ @man = Barr::Manager.new time = Barr::Blocks::Clock.new format: '%H:%M', icon: "\uf017", bgcolor: '#114152', fgcolor: '#DAC1DE', align: :l -date = Barr::Blocks::Clock.new format: '%m of %b %Y', bgcolor: '#570B7A', fgcolor: '#FFFFFF', align: :r, icon: "\uf073" +date = Barr::Blocks::Clock.new format: '%d of %b %Y', bgcolor: '#570B7A', fgcolor: '#FFFFFF', align: :r, icon: "\uf073" @man.add time @man.add date From 007bcc0d56466f3e92a22d08e5a2ca9fa099a3fd Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 4 Mar 2018 00:58:13 +0000 Subject: [PATCH 19/21] Create ISSUE_TEMPLATE.md --- ISSUE_TEMPLATE.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 ISSUE_TEMPLATE.md diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..0ad98ca --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,17 @@ +## Expected Behaviour + + +## Actual Behaviour + + +## Steps or Code to Reproduce the Problem + + 1. + 1. + 1. + +## Specifications + + - Barr Version: + - Lemonbar Version: + - Linux Distro: From e98a2f9a39b48279729fecc98bbd07c8c5ae0d02 Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 4 Mar 2018 01:01:43 +0000 Subject: [PATCH 20/21] Create PULL_REQUEST_TEMPLATE.md --- PULL_REQUEST_TEMPLATE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..99b946f --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,21 @@ +* **Please check if the PR fulfills these requirements** +- [ ] Tests for the changes have been added (for bug fixes / features) +- [ ] Docs have been added / updated (for bug fixes / features) + +* **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...) + + + +* **What is the current behavior?** (You can also link to an open issue here) + + + +* **What is the new behavior (if this is a feature change)?** + + + +* **Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?) + + + +* **Other information**: From d9318d1041f275232b316d8a1e97f8d83c6cc3b7 Mon Sep 17 00:00:00 2001 From: Dave Russell Date: Sun, 4 Mar 2018 13:10:41 +0000 Subject: [PATCH 21/21] Fix grep for Mem block --- lib/barr/blocks/mem.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/barr/blocks/mem.rb b/lib/barr/blocks/mem.rb index 4b9eb00..3774659 100644 --- a/lib/barr/blocks/mem.rb +++ b/lib/barr/blocks/mem.rb @@ -10,7 +10,7 @@ def update! private def sys_cmd - `free -h | grep 'cache:' | awk '{printf "%s / %sG", $(NF-1), $(NF-1)+$(NF)}'`.chomp + `free -h | grep 'Mem:' | awk '{printf "%s / %sG", $(NF-1), $(NF-1)+$(NF)}'`.chomp end end end