From ef00c1a8f4a0c40db1732dc5dfe08c0516ec926b Mon Sep 17 00:00:00 2001 From: Nathan Kleyn Date: Wed, 2 Dec 2020 10:10:02 +0000 Subject: [PATCH] Update to Ruby 2.7, all deps, migrate to GH actions. Copying changes from other project over at https://github.com/nathankleyn/sliding_window to improve the ease with which I can maintain this project! Note this commit contains a crazy amount of changes to appease Rubocop. --- .github/workflows/publish.yml | 40 +++ .github/workflows/tests.yml | 30 +++ .gitignore | 12 +- .rubocop.yml | 72 ++++- .simplecov | 15 ++ .travis.yml | 3 - Gemfile | 2 + Gemfile.lock | 148 +++++----- README.md | 12 +- Rakefile | 3 + examples/serial_port/motor.rb | 4 +- examples/serial_port/motor_rotation.rb | 4 +- examples/serial_port/no_block.rb | 4 +- examples/usb/motor.rb | 4 +- examples/usb/motor_rotation.rb | 4 +- examples/usb/no_block.rb | 4 +- examples/usb/ultrasonic.rb | 4 +- lego-nxt.gemspec | 35 ++- lib/{lego-nxt.rb => lego_nxt.rb} | 20 +- lib/nxt/commands/base.rb | 9 +- lib/nxt/commands/input.rb | 10 +- lib/nxt/commands/low_speed.rb | 8 +- lib/nxt/commands/output.rb | 4 +- lib/nxt/commands/program.rb | 3 + lib/nxt/commands/sound.rb | 3 + lib/nxt/commands/tone.rb | 3 + .../{connectors => connector}/input/base.rb | 2 + .../{connectors => connector}/input/color.rb | 2 + .../{connectors => connector}/input/touch.rb | 2 + .../input/ultrasonic.rb | 3 + .../{connectors => connector}/output/base.rb | 2 + .../{connectors => connector}/output/motor.rb | 18 +- lib/nxt/exceptions.rb | 2 + lib/nxt/{interfaces => interface}/base.rb | 2 + .../{interfaces => interface}/serial_port.rb | 6 +- lib/nxt/{interfaces => interface}/usb.rb | 3 + lib/nxt/nxt_brick.rb | 2 + lib/nxt/patches/module.rb | 2 + lib/nxt/patches/string.rb | 2 + lib/nxt/protocols/i2c.rb | 18 +- lib/nxt/utils/accessors.rb | 2 + lib/nxt/utils/assertions.rb | 2 + spec/matchers.rb | 2 + spec/nxt/connector/output/motor_spec.rb | 52 ++++ spec/nxt/connectors/output/motor_spec.rb | 48 ---- spec/nxt/interface/serial_port_spec.rb | 119 ++++++++ spec/nxt/interfaces/serial_port_spec.rb | 105 -------- spec/nxt/nxt_brick_spec.rb | 255 +++++++++++------- spec/spec_helper.rb | 10 +- 49 files changed, 712 insertions(+), 409 deletions(-) create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/tests.yml create mode 100644 .simplecov delete mode 100755 .travis.yml rename lib/{lego-nxt.rb => lego_nxt.rb} (58%) rename lib/nxt/{connectors => connector}/input/base.rb (80%) rename lib/nxt/{connectors => connector}/input/color.rb (87%) rename lib/nxt/{connectors => connector}/input/touch.rb (87%) rename lib/nxt/{connectors => connector}/input/ultrasonic.rb (98%) rename lib/nxt/{connectors => connector}/output/base.rb (80%) rename lib/nxt/{connectors => connector}/output/motor.rb (92%) rename lib/nxt/{interfaces => interface}/base.rb (93%) rename lib/nxt/{interfaces => interface}/serial_port.rb (94%) rename lib/nxt/{interfaces => interface}/usb.rb (97%) create mode 100644 spec/nxt/connector/output/motor_spec.rb delete mode 100644 spec/nxt/connectors/output/motor_spec.rb create mode 100644 spec/nxt/interface/serial_port_spec.rb delete mode 100644 spec/nxt/interfaces/serial_port_spec.rb diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..595ec3d --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,40 @@ +name: Publish + +on: + push: + tags: + - 'v*' + +jobs: + build: + name: Publish + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby + uses: actions/setup-ruby@v1 + with: + ruby-version: 2.7 + + - name: Publish to GPR + run: | + mkdir -p $HOME/.gem + touch $HOME/.gem/credentials + chmod 0600 $HOME/.gem/credentials + printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials + gem build *.gemspec + gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem + env: + GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}" + OWNER: ${{ github.repository_owner }} + + - name: Publish to RubyGems + run: | + mkdir -p $HOME/.gem + touch $HOME/.gem/credentials + chmod 0600 $HOME/.gem/credentials + printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials + gem build *.gemspec + gem push *.gem + env: + GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..2daaeaa --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,30 @@ +name: Tests + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + test: + name: Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.7 + - name: Install dependencies + run: bundle install + - name: Run tests + run: bundle exec rspec + - name: Run Rubocop + run: bundle exec rubocop + - name: Update Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index f5e7eb9..2fe23da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ -*.gem +.yardoc +doc/ -/bin -/coverage -/doc -/tmp -/.bundle -/.yardoc +coverage +Gemfile.lock +*.gem diff --git a/.rubocop.yml b/.rubocop.yml index 3ad9b75..664f7cc 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,9 +1,69 @@ -LineLength: - Max: 120 +require: rubocop-rspec + +AllCops: + TargetRubyVersion: 2.7 -MethodLength: - Max: 100 +Layout/LineLength: + Enabled: true + Max: 120 Metrics/BlockLength: - Exclude: - - spec/**/*.rb + Enabled: true + Max: 300 + +Metrics/MethodLength: + Enabled: true + Max: 20 + +RSpec/ExampleLength: + Enabled: true + Max: 20 + +Metrics/AbcSize: + Enabled: true + Max: 20 + +Lint/DuplicateBranch: + Enabled: true + +Lint/DuplicateRegexpCharacterClassElement: + Enabled: true + +Lint/EmptyBlock: + Enabled: true + +Lint/EmptyClass: + Enabled: true + +Lint/NoReturnInBeginEndBlocks: + Enabled: true + +Lint/ToEnumArguments: + Enabled: true + +Lint/UnexpectedBlockArity: + Enabled: true + +Lint/UnmodifiedReduceAccumulator: + Enabled: true + +Style/ArgumentsForwarding: + Enabled: true + +Style/CollectionCompact: + Enabled: true + +Style/DocumentDynamicEvalDefinition: + Enabled: true + +Style/NegatedIfElseCondition: + Enabled: true + +Style/NilLambda: + Enabled: true + +Style/RedundantArgument: + Enabled: true + +Style/SwapValues: + Enabled: true diff --git a/.simplecov b/.simplecov new file mode 100644 index 0000000..9858a7a --- /dev/null +++ b/.simplecov @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'simplecov-lcov' + +SimpleCov::Formatter::LcovFormatter.config do |c| + c.report_with_single_file = true + c.single_report_path = 'coverage/lcov.info' +end + +SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new( + [ + SimpleCov::Formatter::HTMLFormatter, + SimpleCov::Formatter::LcovFormatter + ] +) diff --git a/.travis.yml b/.travis.yml deleted file mode 100755 index aadce85..0000000 --- a/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -script: "bundle exec rspec" -rvm: - - 2.5.1 diff --git a/Gemfile b/Gemfile index fa75df1..7f4f5e9 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + source 'https://rubygems.org' gemspec diff --git a/Gemfile.lock b/Gemfile.lock index bbd1641..0be486a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,110 +1,108 @@ PATH remote: . specs: - lego-nxt (0.2.0) - activesupport (~> 5.2.1) + lego-nxt (0.2.0.pre.1.pre.g83ce604) + activesupport (~> 6.0, >= 6.0.3.4) libusb (~> 0.6.4) serialport (~> 1.3.1) GEM remote: https://rubygems.org/ specs: - activesupport (5.2.1) + activesupport (6.0.3.4) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - ast (2.4.0) - byebug (10.0.2) - coderay (1.1.2) - concurrent-ruby (1.0.5) - coveralls (0.8.22) - json (>= 1.8, < 3) - simplecov (~> 0.16.1) - term-ansicolor (~> 1.3) - thor (~> 0.19.4) - tins (~> 1.6) - diff-lcs (1.3) - docile (1.3.1) - ffi (1.9.25) - filewatcher (1.0.1) - trollop (~> 2.1, >= 2.1.2) - i18n (1.1.0) + zeitwerk (~> 2.2, >= 2.2.2) + ast (2.4.1) + byebug (11.1.3) + coderay (1.1.3) + concurrent-ruby (1.1.7) + diff-lcs (1.4.4) + docile (1.3.2) + ffi (1.13.1) + filewatcher (1.1.1) + optimist (~> 3.0) + i18n (1.8.5) concurrent-ruby (~> 1.0) - jaro_winkler (1.5.1) - json (2.1.0) libusb (0.6.4) ffi (~> 1.0) mini_portile2 (~> 2.1) - method_source (0.9.0) - mini_portile2 (2.3.0) - minitest (5.11.3) - parallel (1.12.1) - parser (2.5.1.2) - ast (~> 2.4.0) - powerpack (0.1.2) - pry (0.11.3) - coderay (~> 1.1.0) - method_source (~> 0.9.0) - pry-byebug (3.6.0) - byebug (~> 10.0) - pry (~> 0.10) + method_source (1.0.0) + mini_portile2 (2.5.0) + minitest (5.14.2) + optimist (3.0.1) + parallel (1.20.1) + parser (2.7.2.0) + ast (~> 2.4.1) + pry (0.13.1) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.9.0) + byebug (~> 11.0) + pry (~> 0.13.0) rainbow (3.0.0) - redcarpet (3.4.0) - rspec (3.8.0) - rspec-core (~> 3.8.0) - rspec-expectations (~> 3.8.0) - rspec-mocks (~> 3.8.0) - rspec-core (3.8.0) - rspec-support (~> 3.8.0) - rspec-expectations (3.8.1) + redcarpet (3.5.0) + regexp_parser (2.0.0) + rexml (3.2.4) + rspec (3.10.0) + rspec-core (~> 3.10.0) + rspec-expectations (~> 3.10.0) + rspec-mocks (~> 3.10.0) + rspec-core (3.10.0) + rspec-support (~> 3.10.0) + rspec-expectations (3.10.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-mocks (3.8.0) + rspec-support (~> 3.10.0) + rspec-mocks (3.10.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-support (3.8.0) - rubocop (0.58.2) - jaro_winkler (~> 1.5.1) + rspec-support (~> 3.10.0) + rspec-support (3.10.0) + rubocop (1.5.0) parallel (~> 1.10) - parser (>= 2.5, != 2.5.1.1) - powerpack (~> 0.1) + parser (>= 2.7.1.5) rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.0) + rexml + rubocop-ast (>= 1.2.0) ruby-progressbar (~> 1.7) - unicode-display_width (~> 1.0, >= 1.0.1) - rubocop-rspec (1.29.0) - rubocop (>= 0.58.0) - ruby-progressbar (1.10.0) + unicode-display_width (>= 1.4.0, < 2.0) + rubocop-ast (1.3.0) + parser (>= 2.7.1.5) + rubocop-rspec (2.0.0) + rubocop (~> 1.0) + rubocop-ast (>= 1.1.0) + ruby-progressbar (1.10.1) serialport (1.3.1) - simplecov (0.16.1) + simplecov (0.20.0) docile (~> 1.1) - json (>= 1.8, < 3) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.2) - term-ansicolor (1.6.0) - tins (~> 1.0) - thor (0.19.4) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.12.3) + simplecov-lcov (0.8.0) + simplecov_json_formatter (0.1.2) thread_safe (0.3.6) - tins (1.16.3) - trollop (2.9.9) - tzinfo (1.2.5) + tzinfo (1.2.8) thread_safe (~> 0.1) - unicode-display_width (1.4.0) - yard (0.9.16) + unicode-display_width (1.7.0) + yard (0.9.25) + zeitwerk (2.4.2) PLATFORMS ruby DEPENDENCIES - coveralls (~> 0.8.22) - filewatcher (~> 1.0.1) + filewatcher (~> 1.1, >= 1.1.1) lego-nxt! - pry-byebug (~> 3.6.0) - redcarpet (~> 3.4.0) - rspec (~> 3.8.0) - rubocop (~> 0.58.2) - rubocop-rspec (~> 1.29.0) - yard (~> 0.9.16) + pry-byebug (~> 3.9, >= 3.9.0) + redcarpet (~> 3.5, >= 3.5.0) + rspec (~> 3.10, >= 3.10.0) + rubocop (~> 1.4, >= 1.4.2) + rubocop-rspec (~> 2.0, >= 2.0.0) + simplecov (~> 0.20, >= 0.20.0) + simplecov-lcov (~> 0.8, >= 0.8.0) + yard (~> 0.9, >= 0.9.25) BUNDLED WITH - 1.16.3 + 2.1.4 diff --git a/README.md b/README.md index e64b2fb..20db9aa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Lego NXT [![Gem Version](https://badge.fury.io/rb/lego-nxt.png)](http://badge.fury.io/rb/lego-nxt) [![Build Status](https://travis-ci.org/nathankleyn/lego-nxt.png)](https://travis-ci.org/nathankleyn/lego-nxt) [![Code Climate](https://codeclimate.com/github/nathankleyn/lego-nxt.png)](https://codeclimate.com/github/nathankleyn/lego-nxt) [![Coverage Status](https://coveralls.io/repos/nathankleyn/lego-nxt/badge.png)](https://coveralls.io/r/nathankleyn/lego-nxt) [![Dependency Status](https://gemnasium.com/nathankleyn/lego-nxt.png)](https://gemnasium.com/nathankleyn/lego-nxt) +# Lego NXT [![Build Status](https://github.com/nathankleyn/lego-nxt/workflows/Tests/badge.svg)](https://github.com/nathankleyn/lego-nxt/actions?query=workflow%3ATests) [![Coverage Status](https://coveralls.io/repos/github/nathankleyn/attr_combined_accessor/badge.svg?branch=master)](https://coveralls.io/github/nathankleyn/lego-nxt?branch=master) [![RubyGems Version](https://img.shields.io/gem/v/lego-nxt.svg)](https://rubygems.org/gems/lego-nxt) > **This gem is under heavy development!** A lot of the below code may not work, and is certainly not guranteed to be reliable if it does! If you need to base a working project on this, I recommend [going back to the `ruby-nxt` gem this work is inspired by](https://github.com/zuk/ruby-nxt) for the time being. @@ -108,12 +108,4 @@ In addition to this, you might find the tests quite helpful. There are currently ## License -The MIT License - -Copyright (c) 2014 Nathan Kleyn - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +This project is licensed [via MIT license](LICENSE). diff --git a/Rakefile b/Rakefile index 3ddc371..ff03c3f 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rake' require 'rake/clean' require 'rdoc/task' @@ -23,6 +25,7 @@ namespace :nxt do devices = Dir['/dev/*NXT*'] raise 'Could not detect any connected NXT bricks.' if devices.empty? + puts "Detected a NXT brick at '#{devices.first}'." end end diff --git a/examples/serial_port/motor.rb b/examples/serial_port/motor.rb index d43f96c..85ff09b 100644 --- a/examples/serial_port/motor.rb +++ b/examples/serial_port/motor.rb @@ -1,4 +1,6 @@ -require 'lego-nxt' +# frozen_string_literal: true + +require 'lego_nxt' # The path to your NXT device, change this to run these examples by using the # environment variable NXT_DEVICE. diff --git a/examples/serial_port/motor_rotation.rb b/examples/serial_port/motor_rotation.rb index 42cb8c5..a93086f 100644 --- a/examples/serial_port/motor_rotation.rb +++ b/examples/serial_port/motor_rotation.rb @@ -1,4 +1,6 @@ -require 'lego-nxt' +# frozen_string_literal: true + +require 'lego_nxt' # The path to your NXT device, change this to run these examples by using the # environment variable NXT_DEVICE. diff --git a/examples/serial_port/no_block.rb b/examples/serial_port/no_block.rb index e364aa7..f2f7ec3 100644 --- a/examples/serial_port/no_block.rb +++ b/examples/serial_port/no_block.rb @@ -1,4 +1,6 @@ -require 'lego-nxt' +# frozen_string_literal: true + +require 'lego_nxt' # The path to your NXT device, change this to run these examples by using the # environment variable NXT_DEVICE. diff --git a/examples/usb/motor.rb b/examples/usb/motor.rb index 740d10d..a18aa2e 100644 --- a/examples/usb/motor.rb +++ b/examples/usb/motor.rb @@ -1,4 +1,6 @@ -require 'lego-nxt' +# frozen_string_literal: true + +require 'lego_nxt' NXTBrick.new(:usb) do |nxt| # This is the important part: with this NXT library, you add all your input diff --git a/examples/usb/motor_rotation.rb b/examples/usb/motor_rotation.rb index 2d06d1a..5fa2a89 100644 --- a/examples/usb/motor_rotation.rb +++ b/examples/usb/motor_rotation.rb @@ -1,4 +1,6 @@ -require 'lego-nxt' +# frozen_string_literal: true + +require 'lego_nxt' NXTBrick.new(:usb) do |nxt| # This is the important part: with this NXT library, you add all your input diff --git a/examples/usb/no_block.rb b/examples/usb/no_block.rb index d6f2980..b098981 100644 --- a/examples/usb/no_block.rb +++ b/examples/usb/no_block.rb @@ -1,4 +1,6 @@ -require 'lego-nxt' +# frozen_string_literal: true + +require 'lego_nxt' nxt = NXTBrick.new(:usb) diff --git a/examples/usb/ultrasonic.rb b/examples/usb/ultrasonic.rb index 3dab14a..a90a7ad 100644 --- a/examples/usb/ultrasonic.rb +++ b/examples/usb/ultrasonic.rb @@ -1,4 +1,6 @@ -require 'lego-nxt' +# frozen_string_literal: true + +require 'lego_nxt' NXTBrick.new(:usb) do |nxt| nxt.add_ultrasonic_input(:one, :sonar) diff --git a/lego-nxt.gemspec b/lego-nxt.gemspec index e4d095c..aa8cffb 100644 --- a/lego-nxt.gemspec +++ b/lego-nxt.gemspec @@ -1,9 +1,18 @@ +# frozen_string_literal: true + Gem::Specification.new do |gem| gem.name = 'lego-nxt' - gem.version = '0.2.0' + + # If current commit is tagged, that will be our version. + # Otherwise we'll get some suffixed version, eg. 1.1.2-1-g0fc2ecd + # Which represents a "distance" we are away from the last tag. + # + # Notice we tag as 'v1.2.3' but the gemspec expects just '1.2.3' so + # we have to strip the prefix. + gem.version = `git describe --tags`.chomp.delete_prefix('v') gem.extra_rdoc_files = ['README.md'] gem.summary = 'Ruby LEGO Mindstorms NXT 2.0 control via Bluetooth and USB.' - gem.description = gem.summary + ' See http://github.com/nathankleyn/lego-nxt for more information.' + gem.description = "#{gem.summary} See http://github.com/nathankleyn/lego-nxt for more information." gem.license = 'MIT' gem.author = 'Nathan Kleyn' gem.email = 'nathan@nathankleyn.com' @@ -11,15 +20,19 @@ Gem::Specification.new do |gem| gem.files = %w[README.md Rakefile] + Dir.glob('{lib,spec}/**/*') gem.require_path = 'lib' - gem.add_dependency 'activesupport', '~>5.2.1' + gem.required_ruby_version = '>= 2.7.2' + + gem.add_dependency 'activesupport', '~> 6.0', '>= 6.0.3.4' gem.add_dependency 'libusb', '~>0.6.4' gem.add_dependency 'serialport', '~>1.3.1' - gem.add_development_dependency 'coveralls', '~> 0.8.22' - gem.add_development_dependency 'filewatcher', '~> 1.0.1' - gem.add_development_dependency 'pry-byebug', '~> 3.6.0' - gem.add_development_dependency 'redcarpet', '~> 3.4.0' - gem.add_development_dependency 'rspec', '~> 3.8.0' - gem.add_development_dependency 'rubocop', '~> 0.58.2' - gem.add_development_dependency 'rubocop-rspec', '~> 1.29.0' - gem.add_development_dependency 'yard', '~> 0.9.16' + + gem.add_development_dependency 'filewatcher', '~> 1.1', '>= 1.1.1' + gem.add_development_dependency 'pry-byebug', '~> 3.9', '>= 3.9.0' + gem.add_development_dependency 'redcarpet', '~> 3.5', '>= 3.5.0' + gem.add_development_dependency 'rspec', '~> 3.10', '>= 3.10.0' + gem.add_development_dependency 'rubocop', '~> 1.4', '>= 1.4.2' + gem.add_development_dependency 'rubocop-rspec', '~> 2.0', '>= 2.0.0' + gem.add_development_dependency 'simplecov', '~> 0.20', '>= 0.20.0' + gem.add_development_dependency 'simplecov-lcov', '~> 0.8', '>= 0.8.0' + gem.add_development_dependency 'yard', '~> 0.9', '>= 0.9.25' end diff --git a/lib/lego-nxt.rb b/lib/lego_nxt.rb similarity index 58% rename from lib/lego-nxt.rb rename to lib/lego_nxt.rb index 0fe08f1..6dccdb8 100644 --- a/lib/lego-nxt.rb +++ b/lib/lego_nxt.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + $LOAD_PATH.unshift(File.dirname(__FILE__)) require 'active_support/inflector' @@ -10,9 +12,9 @@ require 'nxt/utils/assertions' require 'nxt/utils/accessors' -require 'nxt/interfaces/base' -require 'nxt/interfaces/usb' -require 'nxt/interfaces/serial_port' +require 'nxt/interface/base' +require 'nxt/interface/usb' +require 'nxt/interface/serial_port' require 'nxt/protocols/i2c' @@ -24,11 +26,11 @@ require 'nxt/commands/sound' require 'nxt/commands/tone' -require 'nxt/connectors/input/base' -require 'nxt/connectors/input/color' -require 'nxt/connectors/input/touch' -require 'nxt/connectors/input/ultrasonic' -require 'nxt/connectors/output/base' -require 'nxt/connectors/output/motor' +require 'nxt/connector/input/base' +require 'nxt/connector/input/color' +require 'nxt/connector/input/touch' +require 'nxt/connector/input/ultrasonic' +require 'nxt/connector/output/base' +require 'nxt/connector/output/motor' require 'nxt/nxt_brick' diff --git a/lib/nxt/commands/base.rb b/lib/nxt/commands/base.rb index dad3fc1..77b1258 100644 --- a/lib/nxt/commands/base.rb +++ b/lib/nxt/commands/base.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Command # The base implementation of all commands, providing low-level details that @@ -51,14 +53,15 @@ def port_as_byte(port) PORTS[port] end - def send_and_receive(command_identifier, payload = [], response_required = true) + def send_and_receive(command_identifier, payload = [], response_required: true) send(command_identifier, payload, response_required) # We bail unless we need to wait for response. return unless response_required + receive end - def send(command_identifier, payload = [], response_required = true) + def send(command_identifier, payload = [], response_required: true) command_identifier |= 0x80 unless response_required @interface.send([ @@ -75,7 +78,7 @@ def receive raise 'Not a valid response to the command that was sent.' unless response[1] == command_identifier raise ERRORS[response[2]] unless response[2].zero? - response[3..-1] + response[3..] end end end diff --git a/lib/nxt/commands/input.rb b/lib/nxt/commands/input.rb index b599c5f..b4bb494 100644 --- a/lib/nxt/commands/input.rb +++ b/lib/nxt/commands/input.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Command # An implementation of all the input related NXT commands: @@ -68,7 +70,7 @@ def command_type COMMAND_TYPES[:direct] end - def update_input_mode(response_required = false) + def update_input_mode(response_required: false) send_and_receive( COMMAND_IDENTIFIER[:set_input_mode], [ @@ -89,15 +91,15 @@ def reset_input_scaled_value send_and_receive(COMMAND_IDENTIFIER[:reset_input_scaled_value], [], response_required) end - def ls_get_status(response_required = false) + def ls_get_status(response_required: false) send_and_receive(COMMAND_IDENTIFIER[:ls_get_status], [], response_required) end - def ls_write(bytes, response_required = false) + def ls_write(bytes, response_required: false) send_and_receive(COMMAND_IDENTIFIER[:ls_write], bytes, response_required) end - def ls_read(response_required = false) + def ls_read(response_required: false) send_and_receive(COMMAND_IDENTIFIER[:ls_read], [], response_required) end end diff --git a/lib/nxt/commands/low_speed.rb b/lib/nxt/commands/low_speed.rb index 385f6f6..03f3b80 100644 --- a/lib/nxt/commands/low_speed.rb +++ b/lib/nxt/commands/low_speed.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Command # An implementation of all the low speed I2C related NXT commands: @@ -29,15 +31,15 @@ def ls_clear_buffer nil end - def ls_get_status(response_required = false) + def ls_get_status(response_required: false) send_and_receive(COMMAND_IDENTIFIER[:ls_get_status], [], response_required) end - def ls_write(response_required = false) + def ls_write(response_required: false) send_and_receive(COMMAND_IDENTIFIER[:ls_write], [], response_required) end - def ls_read(response_required = false) + def ls_read(response_required: false) send_and_receive(COMMAND_IDENTIFIER[:ls_read], [], response_required) end end diff --git a/lib/nxt/commands/output.rb b/lib/nxt/commands/output.rb index 0580108..439641f 100644 --- a/lib/nxt/commands/output.rb +++ b/lib/nxt/commands/output.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'nxt/utils/accessors' module NXT @@ -85,7 +87,7 @@ def command_type COMMAND_TYPES[:direct] end - def update_output_state(response_required = false) + def update_output_state(response_required: false) # Pack this value into a 32-bit unsigned little-endian binary string, # then unpack it into 4 8 bit unsigned integer chunks. We are # converting the passed in value to a little endian, unsigned long diff --git a/lib/nxt/commands/program.rb b/lib/nxt/commands/program.rb index e69de29..079267d 100644 --- a/lib/nxt/commands/program.rb +++ b/lib/nxt/commands/program.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +# FIXME: Create commands for program. diff --git a/lib/nxt/commands/sound.rb b/lib/nxt/commands/sound.rb index e69de29..65ab92a 100644 --- a/lib/nxt/commands/sound.rb +++ b/lib/nxt/commands/sound.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +# FIXME: Create commands for sound. diff --git a/lib/nxt/commands/tone.rb b/lib/nxt/commands/tone.rb index e69de29..1703e1b 100644 --- a/lib/nxt/commands/tone.rb +++ b/lib/nxt/commands/tone.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +# FIXME: Create commands for tone. diff --git a/lib/nxt/connectors/input/base.rb b/lib/nxt/connector/input/base.rb similarity index 80% rename from lib/nxt/connectors/input/base.rb rename to lib/nxt/connector/input/base.rb index 9c4ab82..038b50d 100644 --- a/lib/nxt/connectors/input/base.rb +++ b/lib/nxt/connector/input/base.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Connector # Holds implementations of connectors that are input based. diff --git a/lib/nxt/connectors/input/color.rb b/lib/nxt/connector/input/color.rb similarity index 87% rename from lib/nxt/connectors/input/color.rb rename to lib/nxt/connector/input/color.rb index 01dd498..c59d3d6 100644 --- a/lib/nxt/connectors/input/color.rb +++ b/lib/nxt/connector/input/color.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Connector module Input diff --git a/lib/nxt/connectors/input/touch.rb b/lib/nxt/connector/input/touch.rb similarity index 87% rename from lib/nxt/connectors/input/touch.rb rename to lib/nxt/connector/input/touch.rb index 4a880e2..40f055b 100644 --- a/lib/nxt/connectors/input/touch.rb +++ b/lib/nxt/connector/input/touch.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Connector module Input diff --git a/lib/nxt/connectors/input/ultrasonic.rb b/lib/nxt/connector/input/ultrasonic.rb similarity index 98% rename from lib/nxt/connectors/input/ultrasonic.rb rename to lib/nxt/connector/input/ultrasonic.rb index 54807eb..a2f0649 100644 --- a/lib/nxt/connectors/input/ultrasonic.rb +++ b/lib/nxt/connector/input/ultrasonic.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Connector module Input @@ -44,6 +46,7 @@ def distance def distance! d = distance raise UnmeasurableDistance if d == 255 + d end diff --git a/lib/nxt/connectors/output/base.rb b/lib/nxt/connector/output/base.rb similarity index 80% rename from lib/nxt/connectors/output/base.rb rename to lib/nxt/connector/output/base.rb index 986cea0..c13f8b6 100644 --- a/lib/nxt/connectors/output/base.rb +++ b/lib/nxt/connector/output/base.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Connector # Holds implementations of connectors that are output based. diff --git a/lib/nxt/connectors/output/motor.rb b/lib/nxt/connector/output/motor.rb similarity index 92% rename from lib/nxt/connectors/output/motor.rb rename to lib/nxt/connector/output/motor.rb index 4da0699..0da319d 100644 --- a/lib/nxt/connectors/output/motor.rb +++ b/lib/nxt/connector/output/motor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Connector # Holds implementations of connectors that are output based. @@ -61,9 +63,9 @@ def stop(mode = :coast) # takes block for response, or can return the response instead. def move - update_output_state(duration > 0 && duration_type != :seconds) + update_output_state(duration.positive? && duration_type != :seconds) - if duration > 0 && duration_type == :seconds + if duration.positive? && duration_type == :seconds wait_after_move else reset @@ -84,24 +86,24 @@ def reset private def duration_type=(type) - if !type.nil? + if type.nil? + @duration_type = :seconds + else assert_in(:type, type, DURATION_TYPE) @duration_type = type - else - @duration_type = :seconds end end def duration_after=(after) - if !after.nil? + if after.nil? + @duration_after = :stop + else unless @duration_type == :seconds raise(TypeError, 'The after option is only available when the unit duration is in seconds.') end assert_in(:after, after, DURATION_AFTER) @duration_after = after - else - @duration_after = :stop end end diff --git a/lib/nxt/exceptions.rb b/lib/nxt/exceptions.rb index 23004d4..c53cf8f 100644 --- a/lib/nxt/exceptions.rb +++ b/lib/nxt/exceptions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Exceptions # Raised when a class has not implemented a method from the base class diff --git a/lib/nxt/interfaces/base.rb b/lib/nxt/interface/base.rb similarity index 93% rename from lib/nxt/interfaces/base.rb rename to lib/nxt/interface/base.rb index b6ee65a..9286013 100644 --- a/lib/nxt/interfaces/base.rb +++ b/lib/nxt/interface/base.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Interface # The base implementation of all communication interfaces. This is diff --git a/lib/nxt/interfaces/serial_port.rb b/lib/nxt/interface/serial_port.rb similarity index 94% rename from lib/nxt/interfaces/serial_port.rb rename to lib/nxt/interface/serial_port.rb index 30da140..dc63ea4 100644 --- a/lib/nxt/interfaces/serial_port.rb +++ b/lib/nxt/interface/serial_port.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'serialport' module NXT @@ -15,11 +17,13 @@ class SerialPort < Base READ_TIMEOUT = 5_000 def initialize(dev) + super() self.dev = dev end def dev=(dev) raise InvalidDeviceError unless File.exist?(dev) + @dev = dev end @@ -68,7 +72,7 @@ def receive # # Reference: Appendix 1, Page 22 length = @connection.sysread(2) - @connection.sysread(length.unpack('v')[0]).from_hex_str + @connection.sysread(length.unpack1('v')).from_hex_str end end end diff --git a/lib/nxt/interfaces/usb.rb b/lib/nxt/interface/usb.rb similarity index 97% rename from lib/nxt/interfaces/usb.rb rename to lib/nxt/interface/usb.rb index 9e0d630..99bafb2 100644 --- a/lib/nxt/interfaces/usb.rb +++ b/lib/nxt/interface/usb.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'libusb' module NXT @@ -28,6 +30,7 @@ def connect def disconnect return unless connected? + @connection.release_interface(INTERFACE) @connection.close end diff --git a/lib/nxt/nxt_brick.rb b/lib/nxt/nxt_brick.rb index cdfb20a..235a273 100644 --- a/lib/nxt/nxt_brick.rb +++ b/lib/nxt/nxt_brick.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This class is the entry point for end-users creating their own list of # commands to execute remotely on a Lego NXT brick. # diff --git a/lib/nxt/patches/module.rb b/lib/nxt/patches/module.rb index 6fef0eb..6fbb4ee 100644 --- a/lib/nxt/patches/module.rb +++ b/lib/nxt/patches/module.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Some patches that extend the default Ruby Module with some useful methods. class Module # Creates an invariant accessor that allows getting and setting from the same diff --git a/lib/nxt/patches/string.rb b/lib/nxt/patches/string.rb index 6486334..9658d43 100644 --- a/lib/nxt/patches/string.rb +++ b/lib/nxt/patches/string.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Some patches that extend the default Ruby String class with some useful # methods. class String diff --git a/lib/nxt/protocols/i2c.rb b/lib/nxt/protocols/i2c.rb index f98245c..3159cae 100644 --- a/lib/nxt/protocols/i2c.rb +++ b/lib/nxt/protocols/i2c.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Protocols # Communication to the NXT brick for digital sensors is done using the I2C @@ -28,14 +30,14 @@ module I2C I2C_VARIABLE_OPS = { read_continuous_measurements_interval: 0x40, read_command_state: 0x41, - read_measurement_byte_0: 0x42, - read_measurement_byte_1: 0x43, - read_measurement_byte_2: 0x44, - read_measurement_byte_3: 0x45, - read_measurement_byte_4: 0x46, - read_measurement_byte_5: 0x47, - read_measurement_byte_6: 0x48, - read_measurement_byte_7: 0x49, + read_measurement_byte_zero: 0x42, + read_measurement_byte_one: 0x43, + read_measurement_byte_two: 0x44, + read_measurement_byte_three: 0x45, + read_measurement_byte_four: 0x46, + read_measurement_byte_five: 0x47, + read_measurement_byte_six: 0x48, + read_measurement_byte_seven: 0x49, read_actual_zero: 0x50, read_actual_scale_factor: 0x51, read_actual_scale_divisor: 0x52 diff --git a/lib/nxt/utils/accessors.rb b/lib/nxt/utils/accessors.rb index ead8a23..905f3de 100644 --- a/lib/nxt/utils/accessors.rb +++ b/lib/nxt/utils/accessors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Utils # Utilities related to creating accessors that have some conditonal guards diff --git a/lib/nxt/utils/assertions.rb b/lib/nxt/utils/assertions.rb index 6982c90..931b62d 100644 --- a/lib/nxt/utils/assertions.rb +++ b/lib/nxt/utils/assertions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NXT module Utils # Utilities related to asserting values are what is expected. diff --git a/spec/matchers.rb b/spec/matchers.rb index d47cd5a..7f4c980 100644 --- a/spec/matchers.rb +++ b/spec/matchers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rspec/expectations' RSpec::Matchers.define :have_constant do |expected| diff --git a/spec/nxt/connector/output/motor_spec.rb b/spec/nxt/connector/output/motor_spec.rb new file mode 100644 index 0000000..3db9f9a --- /dev/null +++ b/spec/nxt/connector/output/motor_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe NXT::Connector::Output::Motor do + subject(:motor) { described_class.new(port, interface) } + + let(:port) { :a } + let(:interface) { nil } + + describe 'constants' do + it 'has a DURATION_TYPE constant' do + expect(motor).to have_constant(:DURATION_TYPE) + end + + it 'has a DURATION_AFTER constant' do + expect(motor).to have_constant(:DURATION_AFTER) + end + + it 'has a DIRECTION constant' do + expect(motor).to have_constant(:DIRECTION) + end + end + + describe 'accessors' do + it 'has read accessor for @port' do + expect(motor).to respond_to(:port) + end + + it 'has write accessor for @port' do + expect(motor).to respond_to(:port=) + end + + it 'has read accessor for @interface' do + expect(motor).to respond_to(:interface) + end + + it 'has write accessor for @interface' do + expect(motor).to respond_to(:interface=) + end + end + + describe '#initialize' do + it 'sets the port to the incomming argument' do + expect(motor.port).to equal(port) + end + + it 'sets the interface to the incomming argument' do + expect(motor.interface).to equal(interface) + end + end +end diff --git a/spec/nxt/connectors/output/motor_spec.rb b/spec/nxt/connectors/output/motor_spec.rb deleted file mode 100644 index de03057..0000000 --- a/spec/nxt/connectors/output/motor_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -require 'spec_helper' - -describe NXT::Connector::Output::Motor do - before do - @port = :a - @interface = nil - end - - subject do - NXT::Connector::Output::Motor.new(@port, @interface) - end - - describe 'constants' do - it 'should have a DURATION_TYPE constant' do - should have_constant(:DURATION_TYPE) - end - - it 'should have a DURATION_AFTER constant' do - should have_constant(:DURATION_AFTER) - end - - it 'should have a DIRECTION constant' do - should have_constant(:DIRECTION) - end - end - - describe 'accessors' do - it 'should have read/write accessor for @port' do - should respond_to(:port) - should respond_to(:port=) - end - - it 'should have read/write accessor for @interface' do - should respond_to(:interface) - should respond_to(:interface=) - end - end - - describe '#initialize' do - it 'should set the port to the incomming argument' do - expect(subject.port).to equal(@port) - end - - it 'should set the interface to the incomming argument' do - expect(subject.interface).to equal(@interface) - end - end -end diff --git a/spec/nxt/interface/serial_port_spec.rb b/spec/nxt/interface/serial_port_spec.rb new file mode 100644 index 0000000..fbc4a0e --- /dev/null +++ b/spec/nxt/interface/serial_port_spec.rb @@ -0,0 +1,119 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe NXT::Interface::SerialPort do + subject(:serial_port) { described_class.new(device) } + + let(:device) { '/dev/zero' } + + describe 'constants' do + it 'has a BAUD_RATE constant' do + expect(serial_port).to have_constant(:BAUD_RATE) + end + + it 'has a DATA_BITS constant' do + expect(serial_port).to have_constant(:DATA_BITS) + end + + it 'has a STOP_BITS constant' do + expect(serial_port).to have_constant(:STOP_BITS) + end + + it 'has a PARITY constant' do + expect(serial_port).to have_constant(:PARITY) + end + + it 'has a READ_TIMEOUT constant' do + expect(serial_port).to have_constant(:READ_TIMEOUT) + end + end + + describe 'accessors' do + it 'has read accessor for @dev' do + expect(serial_port).to respond_to(:dev) + end + + it 'has write accessor for @dev' do + expect(serial_port).to respond_to(:dev=) + end + end + + describe '#initialize' do + it 'sets the device to the incomming argument' do + expect(serial_port.dev).to equal(device) + end + + it 'raises an exception when trying to connect to invalid dev files' do + expect do + serial_port.class.new('/dev/foobar') + end.to raise_exception(InvalidDeviceError) + end + end + + describe '#connect' do + it 'raises an exception when the SerialPort connection failed' do + expect do + serial_port.connect + end.to raise_exception(SerialPortConnectionError, "The #{device} device is not a valid SerialPort") + end + + it 'raises an exception when the SerialPort connection is nil' do + allow(::SerialPort).to receive(:new).and_return(nil) + expect do + serial_port.connect + end.to raise_exception(SerialPortConnectionError, "Could not establish a SerialPort connection to #{device}") + end + + it 'sets the flow control and read timeout when the connection is established' do + serial_port_stub = double + allow(serial_port_stub).to receive(:flow_control=).with(::SerialPort::HARD).once + allow(serial_port_stub).to receive(:read_timeout=).with(serial_port.class::READ_TIMEOUT).once + allow(::SerialPort).to receive(:new).and_return(serial_port_stub) + + serial_port.connect + end + end + + describe '#disconnect' do + let(:connection_klass) do + Class.new do + def initialize(closed) + @closed = closed + end + + def closed? + @closed + end + end + end + + it 'closes the connection if connected' do + connection = connection_klass.new(false) + allow(connection).to receive(:close) + serial_port.instance_variable_set(:@connection, connection) + + serial_port.disconnect + + expect(connection).to have_received(:close) + end + + it 'does not close the connection if already disconnected' do + connection = connection_klass.new(true) + allow(connection).to receive(:close) + serial_port.instance_variable_set(:@connection, connection) + + serial_port.disconnect + + expect(connection).not_to have_received(:close) + end + end + + # describe '#send' do + + # end + + # describe '#receive' do + + # end +end diff --git a/spec/nxt/interfaces/serial_port_spec.rb b/spec/nxt/interfaces/serial_port_spec.rb deleted file mode 100644 index 3e08c2a..0000000 --- a/spec/nxt/interfaces/serial_port_spec.rb +++ /dev/null @@ -1,105 +0,0 @@ -require 'spec_helper' - -describe NXT::Interface::SerialPort do - before do - @device = '/dev/zero' - end - - subject do - NXT::Interface::SerialPort.new(@device) - end - - describe 'constants' do - it 'should have a BAUD_RATE constant' do - should have_constant(:BAUD_RATE) - end - - it 'should have a DATA_BITS constant' do - should have_constant(:DATA_BITS) - end - - it 'should have a STOP_BITS constant' do - should have_constant(:STOP_BITS) - end - - it 'should have a PARITY constant' do - should have_constant(:PARITY) - end - - it 'should have a READ_TIMEOUT constant' do - should have_constant(:READ_TIMEOUT) - end - end - - describe 'accessors' do - it 'should have read/write accessor for @dev' do - should respond_to(:dev) - should respond_to(:dev=) - end - end - - describe '#initialize' do - it 'should set the device to the incomming argument' do - expect(subject.dev).to equal(@device) - end - - it 'should raise an exception when trying to connect to invalid dev files' do - expect do - subject.class.new('/dev/foobar') - end.to raise_exception(InvalidDeviceError) - end - end - - describe '#connect' do - it 'should raise an exception when the SerialPort connection failed' do - expect do - subject.connect - end.to raise_exception(SerialPortConnectionError, "The #{@device} device is not a valid SerialPort") - end - - it 'should raise an exception when the SerialPort connection is nil' do - allow(::SerialPort).to receive(:new).and_return(nil) - expect do - subject.connect - end.to raise_exception(SerialPortConnectionError, "Could not establish a SerialPort connection to #{@device}") - end - - it 'should set the flow control and read timeout when the connection is established' do - serial_port_stub = double - allow(serial_port_stub).to receive(:flow_control=).with(::SerialPort::HARD).once - allow(serial_port_stub).to receive(:read_timeout=).with(subject.class::READ_TIMEOUT).once - allow(::SerialPort).to receive(:new).and_return(serial_port_stub) - - subject.connect - end - end - - describe '#disconnect' do - before do - @connection = Object.new - subject.instance_variable_set(:@connection, @connection) - end - - it 'should close the connection if connected' do - expect(subject).to receive(:connected?).and_return(true) - expect(@connection).to receive(:close) - - subject.disconnect - end - - it 'should not close the connection if already disconnected' do - expect(subject).to receive(:connected?).and_return(false) - expect(@connection).to_not receive(:close) - - subject.disconnect - end - end - - # describe '#send' do - - # end - - # describe '#receive' do - - # end -end diff --git a/spec/nxt/nxt_brick_spec.rb b/spec/nxt/nxt_brick_spec.rb index c5b7a87..9ae57c3 100644 --- a/spec/nxt/nxt_brick_spec.rb +++ b/spec/nxt/nxt_brick_spec.rb @@ -1,213 +1,274 @@ +# frozen_string_literal: true + require 'spec_helper' describe NXTBrick do - subject do - NXTBrick.new(:usb) - end + subject(:nxt_brick) { described_class.new(:usb) } describe 'accessors' do - it 'should have read/write accessors for @interface' do - should respond_to(:interface) - should respond_to(:interface=) + it 'has a read accessor for @interface' do + expect(nxt_brick).to respond_to(:interface) + end + + it 'has write accessor for @interface' do + expect(nxt_brick).to respond_to(:interface=) + end + + it 'has a read accessor for @a' do + expect(nxt_brick).to respond_to(:a) + end + + it 'has a write accessor for @a' do + expect(nxt_brick).not_to respond_to(:a=) + end + + it 'has a read accessor for @b' do + expect(nxt_brick).to respond_to(:b) + end + + it 'has a write accessor for @b' do + expect(nxt_brick).not_to respond_to(:b=) end - it 'should have a read accessor for @a' do - should respond_to(:a) - should_not respond_to(:a=) + it 'has a read accessor for @c' do + expect(nxt_brick).to respond_to(:c) end - it 'should have a read accessor for @b' do - should respond_to(:b) - should_not respond_to(:b=) + it 'has a write accessor for @c' do + expect(nxt_brick).not_to respond_to(:c=) end - it 'should have a read accessor for @c' do - should respond_to(:c) - should_not respond_to(:c=) + it 'has a read accessor for @one' do + expect(nxt_brick).to respond_to(:one) end - it 'should have a read accessor for @one' do - should respond_to(:one) - should_not respond_to(:one=) + it 'has a write accessor for @one' do + expect(nxt_brick).not_to respond_to(:one=) end - it 'should have a read accessor for @two' do - should respond_to(:two) - should_not respond_to(:two=) + it 'has a read accessor for @two' do + expect(nxt_brick).to respond_to(:two) end - it 'should have a read accessor for @three' do - should respond_to(:three) - should_not respond_to(:three=) + it 'has a write accessor for @two' do + expect(nxt_brick).not_to respond_to(:two=) end - it 'should have a read accessor for @four' do - should respond_to(:four) - should_not respond_to(:four=) + it 'has a read accessor for @three' do + expect(nxt_brick).to respond_to(:three) end - it 'should have a read accessor for @port_identifiers' do - should respond_to(:port_identifiers) - should_not respond_to(:port_identifiers=) + it 'has a write accessor for @three' do + expect(nxt_brick).not_to respond_to(:three=) + end + + it 'has a read accessor for @four' do + expect(nxt_brick).to respond_to(:four) + end + + it 'has a write accessor for @four' do + expect(nxt_brick).not_to respond_to(:four=) + end + + it 'has a read accessor for @port_identifiers' do + expect(nxt_brick).to respond_to(:port_identifiers) + end + + it 'has a write accessor for @port_identifiers' do + expect(nxt_brick).not_to respond_to(:port_identifiers=) end end describe '#initialize' do - it 'should raise an exception if an invalid type of interface is given' do + it 'raises an exception if an invalid type of interface is given' do expect do - NXTBrick.new(:foobar) + described_class.new(:foobar) end.to raise_exception(InvalidInterfaceError) end - it 'should set the interface to the incomming argument' do - expect(subject.interface).to be_an_instance_of(NXT::Interface::Usb) + it 'sets the interface to the incomming argument' do + expect(nxt_brick.interface).to be_an_instance_of(NXT::Interface::Usb) end - it 'should call yield if given a block, passing self' do + it 'calls yield if given a block, passing self' do block_called = false + # rubocop:disable RSpec/AnyInstance allow_any_instance_of(NXT::Interface::Usb).to receive(:connect) + # rubocop:enable RSpec/AnyInstance - NXTBrick.new(:usb) do |nxt| + described_class.new(:usb) do |_nxt| block_called = true - expect(nxt).to be_an_instance_of(NXTBrick) end expect(block_called).to be true end + + it 'passes self if given a block' do + # rubocop:disable RSpec/AnyInstance + allow_any_instance_of(NXT::Interface::Usb).to receive(:connect) + # rubocop:enable RSpec/AnyInstance + + described_class.new(:usb) do |nxt| + expect(nxt).to be_an_instance_of(described_class) + end + end end describe '#connect' do + let(:interface) { Object.new } + before do - @interface = Object.new - subject.instance_variable_set(:@interface, @interface) + nxt_brick.instance_variable_set(:@interface, interface) end - it 'should call connect on the interface' do - expect(@interface).to receive(:connect) - subject.connect + it 'calls connect on the interface' do + allow(interface).to receive(:connect) + + nxt_brick.connect + + expect(interface).to have_received(:connect) end end describe '#disconnect' do + let(:interface) { Object.new } + before do - @interface = Object.new - subject.instance_variable_set(:@interface, @interface) + nxt_brick.instance_variable_set(:@interface, interface) end - it 'should call disconnect on the interface' do - expect(@interface).to receive(:disconnect) - subject.disconnect + it 'calls disconnect on the interface' do + allow(interface).to receive(:disconnect) + + nxt_brick.disconnect + + expect(interface).to have_received(:disconnect) end end describe '#add' do - before do - @port = :a - @identifier = :hello - @class_stub = Class.new - - allow(subject).to receive(:define_port_handler_method) + let(:port) { :a } + let(:identifier) { :hello } + let(:class_stub) do + Class.new do + def initialize(*_args) + nil + end + end end - it 'should raise an exception if an invalid port number or letter is given' do + it 'raises an exception if an invalid port number or letter is given' do expect do - subject.add(:invalid_port, @identifier, @class_stub) + nxt_brick.add(:invalid_port, identifier, class_stub) end.to raise_exception(TypeError, 'Expected port to be one of: :a, :b, :c, :one, :two, :three, :four') end - it 'should raise an exception if an invalid type of identifier is given' do + it 'raises an exception if an invalid type of identifier is given' do expect do - subject.add(@port, 123, @class_stub) + nxt_brick.add(port, 123, class_stub) end.to raise_exception(TypeError, 'Expected identifier to respond to: to_sym') end - it 'should raise an exception if an invalid type of klass is given' do + it 'raises an exception if an invalid type of class is given' do expect do - subject.add(@port, @identifier, 'not a class') + nxt_brick.add(port, identifier, 'not a class') end.to raise_exception(TypeError, 'Expected klass to be of type Class') end - it 'should raise an exception if trying to use an identifier that is the name of a defined method' do - allow(subject).to receive(@identifier) - + it 'raises an exception if trying to use an identifier that is the name of a defined method' do expect do - subject.add(@port, @identifier, @class_stub) + nxt_brick.add(port, :add, class_stub) end.to raise_error( InvalidIdentifierError, - "Cannot use identifier #{@identifier}, a method on NXTBrick is already using it." + 'Cannot use identifier add, a method on NXTBrick is already using it.' ) end - it 'should raise an exception if the port given is already set' do - allow(subject).to receive(@identifier) - subject.instance_variable_set(:"@#{@port}", 'some value already there') + it 'raises an exception if the port given is already set' do + nxt_brick.add(port, identifier, class_stub) expect do - subject.add(@port, @identifier, @class_stub) - end.to raise_error(PortTakenError, "Port #{@port} is already set, call remove first") + nxt_brick.add(port, identifier, class_stub) + end.to raise_error(PortTakenError, "Port #{port} is already set, call remove first") end - it 'should call #define_port_handler_method' do - expect(subject).to receive(:define_port_handler_method).with(@port, @identifier, @class_stub) - subject.add(@port, @identifier, @class_stub) + it 'sets up the port if the given port is not alread in use' do + nxt_brick.add(port, identifier, class_stub) + + expect(nxt_brick.send(port)).not_to eq(nil) end end describe '#remove' do - it 'should raise an exception if an invalid type of identifier is given' do + it 'raises an exception if an invalid type of identifier is given' do expect do - subject.remove(123) + nxt_brick.remove(123) end.to raise_exception(TypeError, 'Expected identifier to respond to: to_sym') end - it 'should remove any matching identifiers' do + it 'removes any matching identifiers' do identifier = :hello_world port_identifiers = {} - subject.instance_variable_set(:@port_identifiers, port_identifiers) + nxt_brick.instance_variable_set(:@port_identifiers, port_identifiers) - expect(port_identifiers).to receive(:delete).with(identifier).once - subject.remove(identifier) + allow(port_identifiers).to receive(:delete) + + nxt_brick.remove(identifier) + + expect(port_identifiers).to have_received(:delete).with(identifier).once end - it 'should return a boolean indicating whether it removed anything' do + it 'returns a boolean true if it removed anything' do identifier = :hello_world port_identifiers = {} port_identifiers[identifier] = true - subject.instance_variable_set(:@port_identifiers, port_identifiers) + nxt_brick.instance_variable_set(:@port_identifiers, port_identifiers) - return_value = subject.remove(identifier) + return_value = nxt_brick.remove(identifier) expect(return_value).to be true + end - expect(port_identifiers).to_not include(identifier) + it 'removes the port if it did delete something' do + identifier = :hello_world + port_identifiers = {} + port_identifiers[identifier] = true + nxt_brick.instance_variable_set(:@port_identifiers, port_identifiers) - return_value = subject.remove(identifier) + nxt_brick.remove(identifier) + + expect(port_identifiers).not_to include(identifier) + end + + it 'returns a boolean false if it did not remove anything' do + return_value = nxt_brick.remove(:hello_world) expect(return_value).to be false end end describe '#define_port_handler_method' do - before do - @port = :a - @identifier = :hello - @class_stub = Class.new - allow(@class_stub).to receive(:new) + let(:port) { :a } + let(:identifier) { :hello } + let(:class_stub) do + Class.new do + def initialize(*_args) + nil + end + end end - it 'should create a new instance of the passed klass and store it in the attribute for the given port' do + it 'stores it in the attribute for the given port' do class_return_stub = double - expect(@class_stub).to receive(:new) do - class_return_stub - end.with(@port, an_instance_of(NXT::Interface::Usb)).once + allow(class_stub).to receive(:new) { class_return_stub } - subject.send(:define_port_handler_method, @port, @identifier, @class_stub) + nxt_brick.send(:define_port_handler_method, port, identifier, class_stub) - expect(subject.send(@port)).to equal(class_return_stub) + expect(nxt_brick.send(port)).to equal(class_return_stub) end - it 'should set up the port identifiers correctly' do - subject.send(:define_port_handler_method, @port, @identifier, @class_stub) - expect(subject.port_identifiers[@identifier]).to equal(@port) + it 'sets up the port identifiers correctly' do + nxt_brick.send(:define_port_handler_method, port, identifier, class_stub) + expect(nxt_brick.port_identifiers[identifier]).to equal(port) end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 585d769..bcdc250 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,8 +1,12 @@ -require 'coveralls' -Coveralls.wear! +# frozen_string_literal: true + +if ENV['CI'] + require 'simplecov' + SimpleCov.start +end require 'matchers' -require 'lego-nxt' +require 'lego_nxt' # rubocop:disable Style/MixinUsage include NXT::Exceptions