diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 576ac29..8602d98 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,18 +1,12 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# GitHub recommends pinning actions to a commit SHA. -# To get a newer version, you will need to update the SHA. -# You can also reference a tag or branch, but the action may change without warning. -name: ci +# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake +# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby +name: build on: push: branches: [main] pull_request: - branches: [main] + branches: "*" jobs: lint: @@ -33,7 +27,7 @@ jobs: continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }} steps: - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@ec02537da5712d66d4d50a0f33b7eb52773b5ed1 + - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} - run: bundle install diff --git a/.gitignore b/.gitignore index 9882e3e..e087fe0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,14 @@ -*.gem -*.swp -.DS_Store -.bundle -.config -.ruby-* -.rvmrc -.yardoc -.idea -Gemfile.lock -coverage -pkg/* -tmp +/Gemfile.lock +/.DS_Store +/.bundle/ +/.ruby-* +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ + +# rspec failure tracking +.rspec_status diff --git a/.rspec b/.rspec index 1ba834c..7ceab1a 100644 --- a/.rspec +++ b/.rspec @@ -1,3 +1,3 @@ ---order rand --require rspec/pride --format PrideFormatter +--require spec_helper diff --git a/CHANGES.md b/CHANGELOG.md similarity index 95% rename from CHANGES.md rename to CHANGELOG.md index 824e448..2bb66ae 100644 --- a/CHANGES.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ -# Changelog - All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). + +Active Remote adheres to a shifted version of [semver](https://semver.org/spec/v2.0.0.html) +(a la Rails): major/minor versions shadow Rails [versions](https://guides.rubyonrails.org/maintenance_policy.html#versioning) +since Active Remote depends on specific Rails versions. ## [Unreleased] diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..67fe8ce --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,132 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[INSERT CONTACT METHOD]. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/Gemfile b/Gemfile index 3e807a9..02a4f2b 100644 --- a/Gemfile +++ b/Gemfile @@ -2,3 +2,17 @@ source "https://rubygems.org" # Specify your gem's dependencies in active_remote.gemspec gemspec + +gem "benchmark-ips" + +gem "protobuf-rspec", ">= 1.1.2" + +gem "rake", "~> 13.0" + +gem "rspec-pride", ">= 3.1.0" + +gem "rspec", "~> 3.0" + +gem "simplecov" + +gem "standard", "~> 1.3" diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 5fb6d39..0000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2012 Adam Hutchison - -MIT License - -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. \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..50fa00b --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2012-2024 Adam Hutchison + +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. diff --git a/Rakefile b/Rakefile index 6c4cb5f..4baebc3 100755 --- a/Rakefile +++ b/Rakefile @@ -1,14 +1,17 @@ -#!/usr/bin/env rake +# frozen_string_literal: true + require "bundler/gem_tasks" -require "protobuf/tasks" + require "rspec/core/rake_task" -require "standard/rake" -desc "Run specs" -::RSpec::Core::RakeTask.new(:spec) +desc "Run all examples" +RSpec::Core::RakeTask.new(:spec) do |t| + t.ruby_opts = %w[-w] +end -desc "Run cops and specs (default)" -task default: [:standard, :spec] +require "standard/rake" + +task default: %i[spec standard:fix] desc "Remove protobuf definitions that have been compiled" task :clean do @@ -16,7 +19,9 @@ task :clean do puts "Cleaned" end +require "protobuf/tasks" + desc "Compile spec/support protobuf definitions" task :compile do - ::Rake::Task["protobuf:compile"].invoke("", "spec/support/definitions", "spec/support/protobuf") + Rake::Task["protobuf:compile"].invoke("", "spec/support/definitions", "spec/support/protobuf") end diff --git a/active_remote.gemspec b/active_remote.gemspec index 911cb00..8344085 100644 --- a/active_remote.gemspec +++ b/active_remote.gemspec @@ -1,38 +1,40 @@ -$LOAD_PATH.push File.expand_path("lib", __dir__) -require "active_remote/version" +# frozen_string_literal: true -Gem::Specification.new do |s| - s.name = "active_remote" - s.version = ActiveRemote::VERSION - s.authors = ["Adam Hutchison"] - s.email = ["liveh2o@gmail.com"] - s.homepage = "https://github.com/liveh2o/active_remote" - s.summary = "Active Record for your platform" - s.description = "Active Remote provides Active Record-like object-relational mapping over RPC. It was written for use with Google Protocol Buffers, but could be extended to use any RPC data format." +require_relative "lib/active_remote/version" - s.files = `git ls-files`.split("\n") - s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } - s.require_paths = ["lib"] +Gem::Specification.new do |spec| + spec.version = ActiveRemote::VERSION + spec.name = "active_remote" + spec.authors = ["Adam Hutchison"] + spec.email = ["liveh2o@gmail.com"] - s.required_ruby_version = ">= 3.1.0" + spec.summary = "Active Record for your platform" + spec.description = "Active Remote provides Active Record-like object-relational mapping over RPC. It was written for use with Google Protocol Buffers, but could be extended to use any RPC data format." + spec.homepage = "https://github.com/liveh2o/active_remote" + spec.license = "MIT" + spec.required_ruby_version = ">= 3.1.0" - ## - # Dependencies - # - s.add_dependency "activemodel", "~> 7.2.0" - s.add_dependency "activesupport", "~> 7.2.0" - s.add_dependency "protobuf", ">= 3.0" + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = spec.homepage + spec.metadata["changelog_uri"] = spec.homepage + "/blob/main/CHANGELOG.md" + + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + gemspec = File.basename(__FILE__) + spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls| + ls.readlines("\x0", chomp: true).reject do |f| + (f == gemspec) || + f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile]) + end + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] ## - # Development Dependencies + # Dependencies # - s.add_development_dependency "benchmark-ips" - s.add_development_dependency "protobuf-rspec", ">= 1.1.2" - s.add_development_dependency "pry" - s.add_development_dependency "rspec-its" - s.add_development_dependency "rspec-pride", ">= 3.1.0" - s.add_development_dependency "rspec", ">= 3.3.0" - s.add_development_dependency "simplecov" - s.add_development_dependency "standard" - s.add_development_dependency "rake" + spec.add_dependency "activemodel", "~> 7.2.0" + spec.add_dependency "activesupport", "~> 7.2.0" + spec.add_dependency "protobuf", ">= 3.0" end diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..dce67d8 --- /dev/null +++ b/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/lib/active_remote/association.rb b/lib/active_remote/association.rb index d3eda8d..edde9a7 100644 --- a/lib/active_remote/association.rb +++ b/lib/active_remote/association.rb @@ -74,6 +74,8 @@ def belongs_to(belongs_to_klass, options = {}) # end # def has_many(has_many_class, options = {}) + options[:has_many] = true + perform_association(has_many_class, options) do |klass, object| foreign_key = options.fetch(:foreign_key) { :"#{object.class.name.demodulize.underscore}_guid" } search_hash = {} @@ -82,9 +84,6 @@ def has_many(has_many_class, options = {}) search_hash.values.any?(&:nil?) ? [] : klass.search(**search_hash) end - - options[:has_many] = true - create_association_writer(has_many_class, options) end # Create a `has_one` association for a given remote resource. @@ -133,15 +132,6 @@ def validate_scoped_attributes(associated_class, object_class, options) private - def create_association_writer(associated_klass, options = {}) - define_method(:"#{associated_klass}=") do |new_value| - raise "New value must be an array" if options[:has_many] == true && new_value.class != Array - - instance_variable_set(:"@#{associated_klass}", new_value) - new_value - end - end - def perform_association(associated_klass, options = {}) define_method(associated_klass) do klass_name = options.fetch(:class_name) { associated_klass } @@ -159,7 +149,12 @@ def perform_association(associated_klass, options = {}) value end - create_association_writer(associated_klass, options) + define_method(:"#{associated_klass}=") do |new_value| + raise "New value must be an array" if options[:has_many] == true && new_value.class != Array + + instance_variable_set(:"@#{associated_klass}", new_value) + new_value + end end end end diff --git a/spec/lib/active_remote/association_spec.rb b/spec/lib/active_remote/association_spec.rb index c71c73b..e092f49 100644 --- a/spec/lib/active_remote/association_spec.rb +++ b/spec/lib/active_remote/association_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ActiveRemote::Association do +RSpec.describe ActiveRemote::Association do let(:record) { double(:record) } let(:records) { [record] } @@ -168,7 +168,7 @@ context "writer method" do context "when new value is not an array" do - it "should raise error" do + it "raises an error" do expect { subject.posts = Post.new }.to raise_error(::RuntimeError, /New value must be an array/) end end @@ -223,7 +223,7 @@ expect(subject.senior_author).to eq record end - it "should create a setter method" do + it "creates a setter method" do expect(subject).to respond_to(:senior_author=) end end diff --git a/spec/lib/active_remote/base_spec.rb b/spec/lib/active_remote/base_spec.rb index 4611a70..08b6fef 100644 --- a/spec/lib/active_remote/base_spec.rb +++ b/spec/lib/active_remote/base_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ActiveRemote::Base do +RSpec.describe ActiveRemote::Base do describe "#initialize" do it "runs callbacks" do expect_any_instance_of(described_class).to receive(:run_callbacks).with(:initialize) diff --git a/spec/lib/active_remote/dirty_spec.rb b/spec/lib/active_remote/dirty_spec.rb index 0c29bdb..5e82114 100644 --- a/spec/lib/active_remote/dirty_spec.rb +++ b/spec/lib/active_remote/dirty_spec.rb @@ -1,29 +1,31 @@ require "spec_helper" -describe ActiveRemote::Dirty do - context "when writing attributes through the setter" do - subject { Post.new(name: "foo") } +RSpec.describe ActiveRemote::Dirty do + context "#attribute=" do + subject(:post) { Post.new(name: "foo") } before do - subject.changes_applied - subject.clear_changes_information + post.changes_applied + post.clear_changes_information end context "when the value changes" do - before { subject.name = "bar" } - - its(:name_changed?) { should be_truthy } + it "tracks changes" do + post.name = "bar" + expect(post.name_changed?).to be(true) + end end context "when the value doesn't change" do - before { subject.name = "foo" } - - its(:name_changed?) { should be_falsey } + it "tracks changes" do + post.name = "foo" + expect(post.name_changed?).to be(false) + end end end - context "when writing attributes directly" do - subject { Post.new(name: "foo") } + describe "#[]=" do + subject(:post) { Post.new(name: "foo") } before do subject.changes_applied @@ -31,27 +33,27 @@ end context "when the value changes" do - before { subject[:name] = "bar" } - - its(:name_changed?) { should be_truthy } + it "tracks changes" do + post[:name] = "bar" + expect(post.name_changed?).to be(true) + end end context "when the value doesn't change" do - before { subject[:name] = "foo" } - - its(:name_changed?) { should be_falsey } + it "tracks changes" do + post[:name] = "foo" + expect(post.name_changed?).to be(false) + end end end describe "#reload" do - subject { Post.new(name: "foo") } + let(:post) { Post.new(name: "foo") } - before do + it "clears changes information" do allow(Post).to receive(:find).and_return(Post.new(name: "foo")) - subject.reload + expect { post.reload }.to change { post.changed? }.to(false) end - - its(:changes) { should be_empty } end describe "#remote" do @@ -64,30 +66,32 @@ end describe "#save" do - let!(:changes) { subject.changes } - - subject { Post.new(name: "foo") } + subject(:post) { Post.new(name: "foo") } before do - allow(subject).to receive(:create_or_update).and_return(true) - subject.save + allow(post).to receive(:create_or_update).and_return(true) end - its(:previous_changes) { should eq changes } - its(:changes) { should be_empty } + it "applies changes" do + changes = post.changes + post.save + expect(post.previous_changes).to eq(changes) + expect(post.changes).to be_empty + end end describe "#save!" do - let!(:changes) { subject.changes } - - subject { Post.new(name: "foo") } + subject(:post) { Post.new(name: "foo") } before do - allow(subject).to receive(:save).and_return(true) - subject.save! + allow(post).to receive(:save).and_return(true) end - its(:previous_changes) { should eq changes } - its(:changes) { should be_empty } + it "applies changes" do + changes = post.changes + post.save! + expect(post.previous_changes).to eq(changes) + expect(post.changes).to be_empty + end end end diff --git a/spec/lib/active_remote/dsl_spec.rb b/spec/lib/active_remote/dsl_spec.rb index 90d8cd9..8d71458 100644 --- a/spec/lib/active_remote/dsl_spec.rb +++ b/spec/lib/active_remote/dsl_spec.rb @@ -1,12 +1,6 @@ require "spec_helper" -# For testing the DSL methods -module Another - class TagService < Protobuf::Rpc::Service - end -end - -describe ActiveRemote::DSL do +RSpec.describe ActiveRemote::DSL do before { reset_dsl_variables(Tag) } after { Tag.service_class Generic::Remote::TagService } diff --git a/spec/lib/active_remote/errors_spec.rb b/spec/lib/active_remote/errors_spec.rb index 529a77d..f78659d 100644 --- a/spec/lib/active_remote/errors_spec.rb +++ b/spec/lib/active_remote/errors_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ::ActiveRemote::RemoteRecordNotSaved do +RSpec.describe ::ActiveRemote::RemoteRecordNotSaved do let(:record) { ::Tag.new } before do diff --git a/spec/lib/active_remote/integration_spec.rb b/spec/lib/active_remote/integration_spec.rb index 5c230a9..d8d5829 100644 --- a/spec/lib/active_remote/integration_spec.rb +++ b/spec/lib/active_remote/integration_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ::ActiveRemote::Integration do +RSpec.describe ::ActiveRemote::Integration do let(:guid) { "GUID-derp" } let(:tag) { ::Tag.new(guid: guid) } diff --git a/spec/lib/active_remote/persistence_spec.rb b/spec/lib/active_remote/persistence_spec.rb index a465d9f..1100c3d 100644 --- a/spec/lib/active_remote/persistence_spec.rb +++ b/spec/lib/active_remote/persistence_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ::ActiveRemote::Persistence do +RSpec.describe ::ActiveRemote::Persistence do let(:response_without_errors) { ::HashWithIndifferentAccess.new(errors: []) } let(:rpc) { ::ActiveRemote::RPCAdapters::ProtobufAdapter.new(::Tag.service_class, ::Tag.endpoints) } @@ -144,13 +144,17 @@ context "when errors are not present" do before { subject.errors.clear } - its(:has_errors?) { should be_falsey } + it "is false" do + expect(subject.has_errors?).to be(false) + end end context "when errors are present" do before { subject.errors.add(:base, :invalid, message: "Boom!") } - its(:has_errors?) { should be_truthy } + it "is true" do + expect(subject.has_errors?).to be(true) + end end end @@ -158,19 +162,25 @@ context "when the record is created through instantiate" do subject { Tag.instantiate(guid: "foo") } - its(:new_record?) { should be_falsey } + it "is false" do + expect(subject.new_record?).to be(false) + end end context "when the record is persisted" do subject { Tag.allocate.instantiate(guid: "foo") } - its(:new_record?) { should be_falsey } + it "is false" do + expect(subject.new_record?).to be(false) + end end context "when the record is not persisted" do subject { Tag.new } - its(:new_record?) { should be_truthy } + it "is true" do + expect(subject.new_record?).to be(true) + end end end @@ -178,13 +188,17 @@ context "when the record is persisted" do subject { Tag.allocate.instantiate(guid: "foo") } - its(:persisted?) { should be_truthy } + it "is true" do + expect(subject.persisted?).to be(true) + end end context "when the record is not persisted" do subject { Tag.new } - its(:persisted?) { should be_falsey } + it "is false" do + expect(subject.persisted?).to be(false) + end end end @@ -192,8 +206,9 @@ context "when the record is created through instantiate with options[:readonly]" do subject { Tag.instantiate({guid: "foo"}, readonly: true) } - its(:new_record?) { should be_falsey } - its(:readonly?) { should be_truthy } + it "is true" do + expect(subject.readonly?).to be(true) + end end end @@ -332,13 +347,17 @@ context "when errors are present" do before { subject.errors.add(:base, :invalid, message: "Boom!") } - its(:success?) { should be_falsey } + it "is false" do + expect(subject.success?).to be(false) + end end context "when errors are not present" do before { subject.errors.clear } - its(:success?) { should be_truthy } + it "is true" do + expect(subject.success?).to be(true) + end end end diff --git a/spec/lib/active_remote/primary_key_spec.rb b/spec/lib/active_remote/primary_key_spec.rb index 302a42a..92d9b60 100644 --- a/spec/lib/active_remote/primary_key_spec.rb +++ b/spec/lib/active_remote/primary_key_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ActiveRemote::PrimaryKey do +RSpec.describe ActiveRemote::PrimaryKey do let(:tag) { Tag.new(id: "1234", guid: "TAG-123", user_guid: "USR-123") } after { Tag.instance_variable_set :@primary_key, nil } diff --git a/spec/lib/active_remote/query_attribute_spec.rb b/spec/lib/active_remote/query_attribute_spec.rb index 0f4fc4f..37c1d93 100644 --- a/spec/lib/active_remote/query_attribute_spec.rb +++ b/spec/lib/active_remote/query_attribute_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ::ActiveRemote::QueryAttributes do +RSpec.describe ::ActiveRemote::QueryAttributes do subject { ::Author.new } describe "#query_attribute" do diff --git a/spec/lib/active_remote/rpc_adapters/protobuf_adapter_spec.rb b/spec/lib/active_remote/rpc_adapters/protobuf_adapter_spec.rb index abbe460..ef75f85 100644 --- a/spec/lib/active_remote/rpc_adapters/protobuf_adapter_spec.rb +++ b/spec/lib/active_remote/rpc_adapters/protobuf_adapter_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ActiveRemote::RPCAdapters::ProtobufAdapter do +RSpec.describe ActiveRemote::RPCAdapters::ProtobufAdapter do let(:adapter) { ActiveRemote::RPCAdapters::ProtobufAdapter.new(Tag.service_class, Tag.endpoints) } let(:client) { double(:client) } diff --git a/spec/lib/active_remote/rpc_spec.rb b/spec/lib/active_remote/rpc_spec.rb index 07a7df6..fccb46f 100644 --- a/spec/lib/active_remote/rpc_spec.rb +++ b/spec/lib/active_remote/rpc_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ::ActiveRemote::RPC do +RSpec.describe ::ActiveRemote::RPC do subject { ::Tag.new } describe ".build_from_rpc" do diff --git a/spec/lib/active_remote/scope_keys_spec.rb b/spec/lib/active_remote/scope_keys_spec.rb index a1b9f19..8cc2fa0 100644 --- a/spec/lib/active_remote/scope_keys_spec.rb +++ b/spec/lib/active_remote/scope_keys_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ActiveRemote::ScopeKeys do +RSpec.describe ActiveRemote::ScopeKeys do let(:key) { :user_guid } let(:_scope_keys) { ["user_guid"] } let(:scope_keys) { ["guid"] + _scope_keys } diff --git a/spec/lib/active_remote/search_spec.rb b/spec/lib/active_remote/search_spec.rb index e541ad2..98193ac 100644 --- a/spec/lib/active_remote/search_spec.rb +++ b/spec/lib/active_remote/search_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ActiveRemote::Search do +RSpec.describe ActiveRemote::Search do let(:records) { [Generic::Remote::Tag.new(guid: "123")] } let(:response) { Generic::Remote::Tags.new(records: records) } let(:rpc) { double(:rpc) } diff --git a/spec/lib/active_remote/serialization_spec.rb b/spec/lib/active_remote/serialization_spec.rb index ca5c684..48766aa 100644 --- a/spec/lib/active_remote/serialization_spec.rb +++ b/spec/lib/active_remote/serialization_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ActiveRemote::Serialization do +RSpec.describe ActiveRemote::Serialization do describe ".serialize_records" do let(:records) { [{foo: "bar"}] } diff --git a/spec/lib/active_remote/serializers/protobuf_spec.rb b/spec/lib/active_remote/serializers/protobuf_spec.rb index 4ba13f2..e5fa227 100644 --- a/spec/lib/active_remote/serializers/protobuf_spec.rb +++ b/spec/lib/active_remote/serializers/protobuf_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ActiveRemote::Serializers::Protobuf::Fields do +RSpec.describe ActiveRemote::Serializers::Protobuf::Fields do describe ".from_attributes" do let(:ready_value) { {records: [{name: "Cool Post", errors: [{message: "Boom!"}]}]} } let(:value) { {records: {name: "Cool Post", errors: {message: "Boom!"}}} } @@ -11,7 +11,7 @@ end end -describe ActiveRemote::Serializers::Protobuf::Field do +RSpec.describe ActiveRemote::Serializers::Protobuf::Field do describe ".from_attribute" do context "when field is a repeated message" do let(:field) { Generic::Remote::Posts.get_field(:records) } diff --git a/spec/lib/active_remote/validations_spec.rb b/spec/lib/active_remote/validations_spec.rb index 5dcfe8b..18f3893 100644 --- a/spec/lib/active_remote/validations_spec.rb +++ b/spec/lib/active_remote/validations_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ActiveRemote::Validations do +RSpec.describe ActiveRemote::Validations do let(:invalid_record) { ::Post.new } let(:valid_record) { ::Post.new(name: "test") } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1c58c93..bf0b04b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,29 +1,35 @@ -require "rubygems" -require "bundler" +# frozen_string_literal: true require "simplecov" SimpleCov.start do add_filter "/spec/" end -Bundler.require(:default, :development, :test) +require "active_remote" require "protobuf/rspec" require "support/helpers" - -$LOAD_PATH << ::File.expand_path("../support/protobuf", __FILE__) -require "support/protobuf" require "support/models" +require "support/protobuf" RSpec.configure do |config| config.include Protobuf::RSpec::Helpers - # Turn deprecation warnings into errors with full backtrace. - config.raise_errors_for_deprecations! + # Enable flags like --only-failures and --next-failure + config.example_status_persistence_file_path = ".rspec_status" + + # Disable RSpec exposing methods globally on `Module` and `main` + config.disable_monkey_patching! - # Verifies the existance of any stubbed methods, replaces better_receive and better_stub - # https://www.relishapp.com/rspec/rspec-mocks/v/3-1/docs/verifying-doubles/partial-doubles - config.mock_with :rspec do |mocks| - mocks.verify_partial_doubles = true + config.expect_with :rspec do |c| + c.syntax = :expect end + + # Verify the existence of any stubbed methods + config.mock_with :rspec do |c| + c.verify_partial_doubles = true + end + + # Turn deprecation warnings into errors with full backtrace. + config.raise_errors_for_deprecations! end diff --git a/spec/support/models.rb b/spec/support/models.rb index acb99cb..903b799 100644 --- a/spec/support/models.rb +++ b/spec/support/models.rb @@ -5,3 +5,9 @@ require "support/models/no_attributes" require "support/models/post" require "support/models/tag" + +# For testing the DSL methods +module Another + class TagService < Protobuf::Rpc::Service + end +end diff --git a/spec/support/protobuf/author.pb.rb b/spec/support/protobuf/author.pb.rb index 0dac6bc..09a0df7 100644 --- a/spec/support/protobuf/author.pb.rb +++ b/spec/support/protobuf/author.pb.rb @@ -7,7 +7,7 @@ ## # Imports # -require "error.pb" +require_relative "error.pb" module Generic module Remote diff --git a/spec/support/protobuf/category.pb.rb b/spec/support/protobuf/category.pb.rb index 031ab06..28336ad 100644 --- a/spec/support/protobuf/category.pb.rb +++ b/spec/support/protobuf/category.pb.rb @@ -7,7 +7,7 @@ ## # Imports # -require "error.pb" +require_relative "error.pb" module Generic module Remote diff --git a/spec/support/protobuf/post.pb.rb b/spec/support/protobuf/post.pb.rb index 65e4539..4c77c77 100644 --- a/spec/support/protobuf/post.pb.rb +++ b/spec/support/protobuf/post.pb.rb @@ -7,8 +7,8 @@ ## # Imports # -require "error.pb" -require "category.pb" +require_relative "error.pb" +require_relative "category.pb" module Generic module Remote diff --git a/spec/support/protobuf/tag.pb.rb b/spec/support/protobuf/tag.pb.rb index e2ea8c0..89ea8ee 100644 --- a/spec/support/protobuf/tag.pb.rb +++ b/spec/support/protobuf/tag.pb.rb @@ -7,7 +7,7 @@ ## # Imports # -require "error.pb" +require_relative "error.pb" module Generic module Remote