diff --git a/.gitignore b/.gitignore index 381affa..566793e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ [#]*[#] .\#* .swp +barr-*.gem 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/.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 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: 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**: diff --git a/README.md b/README.md index 566bfc3..30a18d6 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}` | Summary 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. @@ -195,11 +218,29 @@ 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` -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 | + +#### Free Text + +Displays a string of text. Useful for creating a set of clickable areas or creating space. + +`free = Barr::Blocks::FreeText.new text: 'Hello'` + +| Option | Value | Description | Default | +| --- | --- | --- | --- | +| `text` | string | The text to display in the block. Supports Lemonbar syntax | `''` | + #### HDD @@ -211,6 +252,87 @@ 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** | + +#### 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** | +| `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}` | 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. | + +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 **Requires i3wm**. Shows the current workspaces and highlights the active one. You can click a workspace name to change to there. @@ -241,6 +363,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. @@ -250,7 +390,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/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 ddec6fd..71ad2d8 100644 --- a/barr.gemspec +++ b/barr.gemspec @@ -1,40 +1,48 @@ -# 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_runtime_dependency "i3ipc", "0.2.0" - 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) RhythmBox & rhythmbox-client" - spec.requirements << "(Optional) FontAwesome font" + 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' + spec.requirements << '(Optional) mpstat from sysstat' end diff --git a/bin/console b/bin/console index 5e0fd8d..c3bae77 100755 --- 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/bin/setup b/bin/setup old mode 100755 new mode 100644 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 702460f..bb42bee 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,13 +28,13 @@ 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: 60) -cpu = Barr::Blocks::CPU.new icon: "\uf1fe" +cpu = Barr::Blocks::CPU.new icon: "\uf1fe", format: '${LOAD} ${TEMP}' mem = Barr::Blocks::Mem.new bgcolor: '#333333' @@ -47,15 +42,21 @@ 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', + fgcolor: '#EEEEEE' # Left -@man.add artist -@man.add song +@man.add music @man.add weather @man.add cpu @man.add mem @man.add hdd -# Right +# Right +@man.add office_lights @man.add i3 @man.add local @man.add who diff --git a/examples/barr_example.rb b/examples/barr_example.rb index 75b5ead..cd3e2d3 100755 --- 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 index e7c8a51..b68a5c2 100755 --- 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 index f6102c5..5fc3f6d 100755 --- 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 index 0de887b..1fb71da 100755 --- 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 new file mode 100755 index 0000000..4aa92a2 --- /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/examples/hue.rb b/examples/hue.rb new file mode 100755 index 0000000..d2a9d27 --- /dev/null +++ b/examples/hue.rb @@ -0,0 +1,19 @@ +#!/usr/bin/env ruby + +require 'rubygems' +require 'barr' + +@man = Barr::Manager.new + +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}' + +@man.add light +@man.add group + +@man.run! diff --git a/examples/i3_cpu_mem.rb b/examples/i3_cpu_mem.rb index 50ab18b..6b33c08 100755 --- 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 +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 deleted file mode 100755 index d9d0db9..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: 10000 - -@man.add artist -@man.add title -@man.add btns - -@man.run! 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 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/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 new file mode 100755 index 0000000..53a767f --- /dev/null +++ b/exe/barr_open_url @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby + +require 'rubygems' + +cmd = ARGV.join('://').delete('\\') +`xdg-open #{cmd}` diff --git a/lib/barr.rb b/lib/barr.rb index cfc67dd..0ad1f1e 100644 --- a/lib/barr.rb +++ b/lib/barr.rb @@ -1,16 +1,23 @@ 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' require 'barr/blocks/cpu' +require 'barr/blocks/free_text' 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' +require 'barr/blocks/playerctl' require 'barr/blocks/processes' require 'barr/blocks/rhythmbox' require 'barr/blocks/mpd' @@ -18,5 +25,9 @@ require 'barr/blocks/whoami' require 'barr/blocks/separator' +require 'barr/controllers/bbc_weather' +require 'barr/controllers/http_grab' +require 'barr/controllers/playerctl' + module Barr end diff --git a/lib/barr/block.rb b/lib/barr/block.rb index 700def2..1f9c8ab 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 @@ -28,28 +31,57 @@ def draw "#{colors} #{icon} #{@output} #{reset_colors}" end - def destroy! + def destroy!; end + + def update!; end + + def tmp_filename + @tmp_filename ||= "/tmp/barr-#{SecureRandom.uuid}-#{self.class.name.gsub(/::/, '-')}-#{SecureRandom.urlsafe_base64}" + @tmp_filename end - - def update! + + def wrap_button(text, action) + "%{A:#{action}:}#{text}%{A}" end - def tmp_filename - @tmp_filename ||= "/tmp/#{SecureRandom.uuid}-#{self.class.name.gsub(/::/, "-")}-#{SecureRandom.urlsafe_base64}" - return @tmp_filename + def format_string_from_hash(hash, sender = nil) + formatted = @format.clone + matches = @format.scan(/([\$][\{](\w+)(:?([^:\}]+)?)[\}])/) + matches.each do |match| + 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 + + 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 @@ -61,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 new file mode 100644 index 0000000..9581f50 --- /dev/null +++ b/lib/barr/blocks/bbc_weather.rb @@ -0,0 +1,25 @@ +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 https 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 8024363..5b985a5 100644 --- a/lib/barr/blocks/bspwm.rb +++ b/lib/barr/blocks/bspwm.rb @@ -3,65 +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["name"] != @monitor - focused = monitor["focusedDesktopName"] - monitor["desktops"].each do |desktop| - if desktop["name"] == 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["name"].gsub(":","\:")}:} " - 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["primaryMonitorName"] + 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 5c5a54a..2769309 100644 --- a/lib/barr/blocks/cpu.rb +++ b/lib/barr/blocks/cpu.rb @@ -1,21 +1,32 @@ + 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 + # 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`.chomp + end end Cpu = CPU diff --git a/lib/barr/blocks/free_text.rb b/lib/barr/blocks/free_text.rb new file mode 100644 index 0000000..8422910 --- /dev/null +++ b/lib/barr/blocks/free_text.rb @@ -0,0 +1,18 @@ +require 'barr/block' + +module Barr + module Blocks + class FreeText < Block + attr_accessor :text + + def initialize(opts = {}) + super + @text = opts[:text] || '' + end + + def update! + @output = @text + end + end + end +end 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 new file mode 100644 index 0000000..320f35b --- /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].nil? ? false : 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('://', ' ').tr('/', "\/")}:}#{@output}%{A}" if @link + end + end + end +end diff --git a/lib/barr/blocks/hue_group.rb b/lib/barr/blocks/hue_group.rb new file mode 100644 index 0000000..3a187b4 --- /dev/null +++ b/lib/barr/blocks/hue_group.rb @@ -0,0 +1,15 @@ +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/lib/barr/blocks/hue_light.rb b/lib/barr/blocks/hue_light.rb new file mode 100644 index 0000000..aae3c85 --- /dev/null +++ b/lib/barr/blocks/hue_light.rb @@ -0,0 +1,80 @@ +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(/(? <) - @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..3774659 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 @@ -11,9 +10,8 @@ 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 - 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 new file mode 100644 index 0000000..cc862c2 --- /dev/null +++ b/lib/barr/blocks/playerctl.rb @@ -0,0 +1,42 @@ +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).to_s + 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[:buttons] = [ + @btns[:previous], + @btns[:play_pause], + @btns[:previous] + ].join(' ') + end + + @btns + end + end + end +end 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 new file mode 100644 index 0000000..a0d9cc7 --- /dev/null +++ b/lib/barr/controller.rb @@ -0,0 +1,37 @@ +module Barr + class Controller + 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 update! + @output = JSON.parse(`cat #{filename}`, symbolize_names: true) + 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..21cabd2 --- /dev/null +++ b/lib/barr/controllers/bbc_weather.rb @@ -0,0 +1,53 @@ +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 run! + @thread = Thread.new do + loop do + begin + url = "https://www.bbc.co.uk/weather/0/#{@id}" + + op = {} + + noko = Nokogiri::HTML(open(url)) + + 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) + + 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/controllers/http_grab.rb b/lib/barr/controllers/http_grab.rb new file mode 100644 index 0000000..35be0d1 --- /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/lib/barr/controllers/playerctl.rb b/lib/barr/controllers/playerctl.rb new file mode 100644 index 0000000..44818e2 --- /dev/null +++ b/lib/barr/controllers/playerctl.rb @@ -0,0 +1,43 @@ +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/lib/barr/manager.rb b/lib/barr/manager.rb index b96045a..e3bf6a3 100644 --- a/lib/barr/manager.rb +++ b/lib/barr/manager.rb @@ -3,23 +3,38 @@ module Barr class Manager - - ERROR_ICON = "%{F#FF0000}\uf071%{F-}" + ERROR_ICON = "%{F#FF0000}\uf071%{F-}".freeze attr_reader :count, :blocks def initialize @count = 0 @blocks = [] + @controllers = {} end def add(block) block.manager = self @blocks << block + block.config end def destroy! @blocks.each(&:destroy!) + @controllers.each_value(&: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! + + controller end def draw @@ -34,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 @@ -54,29 +69,52 @@ 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 e.message + STDERR.puts e.backtrace block << ERROR_ICON unless block.output.include?(ERROR_ICON) next end end + @controllers.each_value do |controller| + begin + controller.update! if @count == 1 || (@count % controller.interval).zero? + rescue StandardError => e + STDERR.puts 'controller: ' + e.class.name + STDERR.puts e.message + STDERR.puts e.backtrace + next + end + end + @count += 1 end 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 b4059a8..abea2a6 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'.freeze end diff --git a/spec/block_spec.rb b/spec/block_spec.rb index 6299d35..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,19 +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}' } + + 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/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 new file mode 100644 index 0000000..55f18df --- /dev/null +++ b/spec/blocks/bbc_weather_spec.rb @@ -0,0 +1,27 @@ +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 https 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 54600a5..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("DP-4") + 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(10) - expect(subject.tree["monitors"].first["desktops"].first["name"]).to eq("I") + 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("> 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}") + 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}> I <%{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 X:} X %{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 92111d0..4cb5d40 100644 --- a/spec/blocks/cpu_spec.rb +++ b/spec/blocks/cpu_spec.rb @@ -1,18 +1,26 @@ + 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 - end diff --git a/spec/blocks/free_text_spec.rb b/spec/blocks/free_text_spec.rb new file mode 100644 index 0000000..588bab5 --- /dev/null +++ b/spec/blocks/free_text_spec.rb @@ -0,0 +1,14 @@ + +require 'barr/blocks/free_text' + +RSpec.describe Barr::Blocks::FreeText do + describe '#update!' do + + it 'sets the text correctly' do + subject.text = 'Text Test' + subject.update! + expect(subject.output).to eq 'Text Test' + 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 new file mode 100644 index 0000000..873247b --- /dev/null +++ b/spec/blocks/http_grab_spec.rb @@ -0,0 +1,29 @@ +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/blocks/hue_group_spec.rb b/spec/blocks/hue_group_spec.rb new file mode 100644 index 0000000..a81695c --- /dev/null +++ b/spec/blocks/hue_group_spec.rb @@ -0,0 +1,60 @@ + +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 diff --git a/spec/blocks/hue_light_spec.rb b/spec/blocks/hue_light_spec.rb new file mode 100644 index 0000000..80b92bd --- /dev/null +++ b/spec/blocks/hue_light_spec.rb @@ -0,0 +1,60 @@ + +require 'barr/blocks/hue_light' + +RSpec.describe Barr::Blocks::HueLight 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 light 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 light 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 light 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 light 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 light 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 light 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 light 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 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 new file mode 100644 index 0000000..88b1477 --- /dev/null +++ b/spec/blocks/playerctl_spec.rb @@ -0,0 +1,27 @@ +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/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 new file mode 100644 index 0000000..88fc343 --- /dev/null +++ b/spec/mocks/bbc_weather.rb @@ -0,0 +1,32 @@ + +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 diff --git a/spec/mocks/bspwm.rb b/spec/mocks/bspwm.rb index 4e1ec37..24be215 100644 --- a/spec/mocks/bspwm.rb +++ b/spec/mocks/bspwm.rb @@ -1,1630 +1,982 @@ - -$bsp_json = <