diff --git a/.gitignore b/.gitignore index 73b0073..e483dff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ - # rcov generated coverage coverage.data @@ -16,7 +15,7 @@ doc # jeweler generated pkg -# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore: +# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore: # # * Create a file at ~/.gitignore # * Include files you want ignored diff --git a/README.md b/README.md index f0a5147..ad2c698 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ gem install blockscore If you are using Rails, add the following to your `Gemfile`: ```ruby -gem 'blockscore', '~> 4.2.0' +gem 'blockscore', '~> 4.1.2' ``` ## Getting Started @@ -60,5 +60,5 @@ To see the list of calls you can make, please visit our [full Ruby API reference The test suite uses a public BlockScore API key that was created specifically to ease the testing and contribution processes. **Please do not enter personal details for tests.** In order to run the test suite: ```shell -$ rspec spec +$ rake test ``` diff --git a/blockscore.gemspec b/blockscore.gemspec index 0754300..7425d4c 100644 --- a/blockscore.gemspec +++ b/blockscore.gemspec @@ -29,7 +29,6 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 1.0' spec.add_development_dependency 'simplecov', '~> 0' spec.add_development_dependency 'rspec', '~> 3' - spec.add_development_dependency 'rspec-its', '~> 1' spec.add_development_dependency 'webmock', '~> 1.21' spec.add_development_dependency 'faker', '~> 1.4' spec.add_development_dependency 'factory_girl', '~> 4.5' diff --git a/lib/blockscore.rb b/lib/blockscore.rb index 71e547a..b652aa5 100644 --- a/lib/blockscore.rb +++ b/lib/blockscore.rb @@ -1,4 +1,3 @@ -require 'delegate' require 'forwardable' require 'httparty' require 'json' @@ -27,7 +26,6 @@ require 'blockscore/watchlist_hit' require 'blockscore/collection' -require 'blockscore/collection/member' require 'blockscore/connection' require 'blockscore/dispatch' require 'blockscore/fingerprint' @@ -36,7 +34,11 @@ require 'blockscore/version' module BlockScore - class << self - attr_accessor :api_key + def self.api_key=(api_key) + @api_key = api_key + end + + def self.api_key + @api_key end end diff --git a/lib/blockscore/actions/retrieve.rb b/lib/blockscore/actions/retrieve.rb index 87725d7..e0585af 100644 --- a/lib/blockscore/actions/retrieve.rb +++ b/lib/blockscore/actions/retrieve.rb @@ -11,10 +11,8 @@ module Actions # => # module Retrieve module ClassMethods - def retrieve(id, options = {}) - fail ArgumentError if id.empty? - req = ->() { get("#{endpoint}/#{id}", options) } - new(id: id, &req) + def retrieve(id) + get("#{endpoint}/#{id}", {}) end end diff --git a/lib/blockscore/actions/update.rb b/lib/blockscore/actions/update.rb index 1de39ed..df9e25e 100644 --- a/lib/blockscore/actions/update.rb +++ b/lib/blockscore/actions/update.rb @@ -28,7 +28,7 @@ module Update def_delegators 'self.class', :endpoint, :patch def save! - if persisted? + if respond_to? :id patch("#{endpoint}/#{id}", filter_params) true else diff --git a/lib/blockscore/base.rb b/lib/blockscore/base.rb index c24f5c9..b19d657 100644 --- a/lib/blockscore/base.rb +++ b/lib/blockscore/base.rb @@ -4,37 +4,19 @@ module BlockScore class Base extend Connection - def initialize(options = {}, &block) - @loaded = !(block) - @proc = block - @attributes = options - end - - def attributes - return @attributes if @loaded - force! - @attributes - end - - def force! - res = @proc.call - @attributes = res.attributes.merge(@attributes) - @loaded = true - self - end + attr_reader :attributes - def id - @attributes.fetch(:id, nil) + def initialize(options = {}) + @attributes = options end def inspect - str_attr = "JSON:#{JSON.pretty_generate(attributes)}" - "#<#{self.class}:0x#{object_id.to_s(16)} #{str_attr}>" + "#<#{self.class}:0x#{object_id.to_s(16)} JSON: " + JSON.pretty_generate(attributes) end def refresh - res = self.class.retrieve(id) - @attributes = res.attributes + r = self.class.retrieve(id) + @attributes = r.attributes true rescue Error @@ -49,7 +31,6 @@ def save def save! response = self.class.post(self.class.endpoint, attributes) - # binding.pry @attributes = response.attributes true @@ -64,18 +45,16 @@ def self.api_url end def self.endpoint - fail NotImplementedError, 'Base is an abstract class, not an API resource' if equal?(Base) + if self == Base + fail NotImplementedError, 'Base is an abstract class, not an API resource' + end "#{api_url}#{Util.to_plural(resource)}" end - def persisted? - !id.nil? - end - protected - def add_accessor(symbol, *_args) + def add_accessor(symbol, *args) singleton_class.instance_eval do define_method(symbol) do wrap_attribute(attributes[symbol]) diff --git a/lib/blockscore/collection.rb b/lib/blockscore/collection.rb index b1b4f12..e81284d 100644 --- a/lib/blockscore/collection.rb +++ b/lib/blockscore/collection.rb @@ -1,239 +1,18 @@ module BlockScore - # Collection is a proxy between the parent and the asssociated members - # where parent is some instance of a resource - # class Collection < Array - # @!attribute [r] parent - # resource which owns a collection of other resources - # - # @example - # person.question_sets.parent # => person - # - # @return [BlockScore::Base] a resource - # - # @api private - attr_reader :parent - - # Sets parent and member_class then registers embedded ids - # - # @param [BlockScore::Base] parent - # @param [Class] class of collection members - # - # @return [undefined] - # - # @api private - def initialize(parent, member_class) - @parent = parent - @member_class = member_class - register_parent_data - end - - # Syntactic sugar method for returning collection - # - # @example - # all # returns collection - # - # @return [self] - # - # @api public - def all - self - end - - # Initializes new {member_class} with `params` - # - # - Ensures a parent id is meged into `params` (see #default_params). - # - Defines method `#save` on new collection member - # - Adds new item to collection - # - # @example usage - # - # >> person = person = BlockScore::Person.retrieve('55de4af7643735000300000f') - # >> person.question_sets.new - # => # - # - # @param params [Hash] initial params for member - # - # @return instance of {member_class} - # - # @api public - def new(params = {}) - attributes = params.merge(default_params) - instance = member_class.new(attributes) - - new_member(instance) do |member| - self << member - end - end - - # Relaod the contents of the collection - # - # @example usage - # person.question_sets.refresh # => [# 'person' - # - # @return [String] - # - # @api semipublic - def parent_name - parent.class.resource - end - - # Initialize a collection member and save it - # - # @example - # >> person.question_sets.create - # => # instance of QuestionSet - # - # @param id [String] resource id - # - # @return instance of {member_class} if found - # @raise [BlockScore::NotFoundError] otherwise - # - # @api public - def retrieve(id) - each do |item| - next unless item.id == id - return item - end - - instance = member_class.retrieve(id) - - new_member(instance) do |member| - register_to_parent(member) - end - end - - protected - - # @!attribute [r] member_class - # class which will be used for the embedded - # resources in the collection - # - # @return [Class] - # - # @api private - attr_reader :member_class - - # Default params for making an instance of {member_class} - # - # @return [Hash] - # - # @api private - def default_params - { - foriegn_key => parent.id - } + def respond_to?(method, include_all = false) + @target.respond_to?(method, include_all) end private - # Generate foriegn key name for parent resource - # - # @return [Symbol] resource name as id - # - # @api private - def foriegn_key - :"#{parent_name}_id" - end - - # Initialize a new collection member - # - # @param instance [BlockScore::Base] collection member instance - # @yield [Member] initialized member - # - # @return [Member] new member - # - # @api private - def new_member(instance, &blk) - Member.new(parent, instance).tap(&blk) - end - - # Check if `parent_id` is defined on `item` - # - # @param item [BlockScore::Base] any resource - # - # @return [Boolean] - # - # @api private - def parent_id?(item) - parent.id && item.send(foriegn_key) == parent.id - end - - # Register a resource in collection - # - # @param item [BlockScore::Base] a resource - # - # @raise [BlockScore::Error] if no `parent_id` - # @return [BlockScore::Base] otherwise - # - # @api private - def register_to_parent(item) - fail Error, 'None belonging' unless parent_id?(item) - ids << item.id - self << item - item - end - - # Fetches embedded ids from parent and adds to self - # - # @return [undefined] - # - # @api private - def register_parent_data - ids.each do |id| - item = member_class.retrieve(id) - self << item - end - end - - # ids that belong to the collection - # - # @return [Array] - # - # @api private - def ids - parent.attributes.fetch(:"#{Util.to_plural(member_class.resource)}", []) + def method_missing(method, *args, &block) + @target.public_send(method, *args, &block) end end end diff --git a/lib/blockscore/collection/member.rb b/lib/blockscore/collection/member.rb deleted file mode 100644 index ff50e08..0000000 --- a/lib/blockscore/collection/member.rb +++ /dev/null @@ -1,100 +0,0 @@ -module BlockScore - class Collection - # Member of a {Collection} class - class Member < SimpleDelegator - # Initialize a new member - # - # @param parent [BlockScore::Base] parent resource - # @param instance [BlockScore::Base] member instance - # - # @return [undefined] - # - # @api private - def initialize(parent, instance) - @instance = instance - @parent = parent - - super(instance) - end - - # Save parent, set parent id, and save instance - # - # @example - # # saves both unsaved person and unsaved question_set - # person = Person.new(attributes) - # question_set = QuestionSet.new - # Member.new(person, question_set).save - # - # @return return value of instance `#save` - # - # @api public - def save - save_parent - send(:"#{parent_name}_id=", parent.id) - result = instance.save - ids.push(instance.id) unless ids.include?(instance.id) - result - end - - private - - # Name of parent resource - # - # @example - # self.parent_name # => 'person' - # - # @return [String] - # - # @api private - def parent_name - parent.class.resource - end - - # Save parent if it hasn't already been saved - # - # @return return of parent.save if previously unsaved - # @return nil otherwise - # - # @api private - def save_parent - parent.save unless parent_saved? - end - - # Check if parent is saved - # - # @return [Boolean] - # - # @api private - def parent_saved? - parent.id - end - - # @!attribute [r] instance - # member instance methods are delegated to - # - # @return [BlockScore::Base] - # - # @api private - attr_reader :instance - - # @!attribute [r] parent - # collection parent the collectino conditionally updates - # - # @return [BlockScore::Base] - # - # @api private - attr_reader :parent - - private - - # ids that belong to associated parent resource - # - # @return [Array] - # - # @api private - def ids - parent.attributes.fetch(:"#{Util.to_plural(instance.class.resource)}", []) - end - end - end -end diff --git a/lib/blockscore/connection.rb b/lib/blockscore/connection.rb index 9d1c5df..ade3d24 100644 --- a/lib/blockscore/connection.rb +++ b/lib/blockscore/connection.rb @@ -32,7 +32,7 @@ def request(method, path, params) begin response = execute_request(method, path, params) rescue SocketError, Errno::ECONNREFUSED => e - raise APIConnectionError, e.message + fail APIConnectionError, e.message end Response.handle_response(resource, response) @@ -55,7 +55,7 @@ def execute_request(method, path, params) def encode_path_params(path, params) encoded = URI.encode_www_form(params) - [path, encoded].join('?') + [path, encoded].join("?") end end end diff --git a/lib/blockscore/errors/api_error.rb b/lib/blockscore/errors/api_error.rb index 43a6d0d..1b9bd6b 100644 --- a/lib/blockscore/errors/api_error.rb +++ b/lib/blockscore/errors/api_error.rb @@ -15,7 +15,7 @@ class APIError < Error # APIError - Indicates an error on the server side (HTTP 5xx) # AuthenticationError - Indicates an authentication error (HTTP 401) def initialize(response) - body = JSON.parse(response.body, symbolize_names: true) + body = JSON.parse(response.body, :symbolize_names => true) @message = body[:error][:message] @http_status = response.code @@ -24,8 +24,8 @@ def initialize(response) end def to_s - status_string = @http_status ? "(Status: #{@http_status})" : '' - type_string = @error_type ? "(Type: #{@error_type})" : '' + status_string = @http_status ? "(Status: #{@http_status})" : "" + type_string = @error_type ? "(Type: #{@error_type})" : "" "#{type_string} #{@message} #{status_string}" end diff --git a/lib/blockscore/errors/invalid_request_error.rb b/lib/blockscore/errors/invalid_request_error.rb index e7ff856..f76873e 100644 --- a/lib/blockscore/errors/invalid_request_error.rb +++ b/lib/blockscore/errors/invalid_request_error.rb @@ -19,9 +19,9 @@ def initialize(response) end def to_s - status_string = @http_status ? "(Status: #{@http_status})" : '' - type_string = @error_type ? "(Type: #{@error_type})" : '' - param_string = @param ? "(#{@param})" : '' + status_string = @http_status ? "(Status: #{@http_status})" : "" + type_string = @error_type ? "(Type: #{@error_type})" : "" + param_string = @param ? "(#{@param})" : "" "#{type_string} #{@message} #{param_string} #{status_string}" end diff --git a/lib/blockscore/person.rb b/lib/blockscore/person.rb index b26e3a4..ec311a7 100644 --- a/lib/blockscore/person.rb +++ b/lib/blockscore/person.rb @@ -11,7 +11,7 @@ class Person < Base def initialize(options = {}) super - @question_sets = Collection.new(self, QuestionSet) + @question_sets = Collection.new(QuestionSet.new(person: self)) end def valid? diff --git a/lib/blockscore/question_set.rb b/lib/blockscore/question_set.rb index c79ab0c..944230d 100644 --- a/lib/blockscore/question_set.rb +++ b/lib/blockscore/question_set.rb @@ -6,7 +6,14 @@ class QuestionSet < Base include BlockScore::Actions::Retrieve include BlockScore::Actions::All - def_delegators 'self.class', :post, :endpoint + def_delegators 'self.class', :retrieve, :all, :post, :endpoint + + def create + result = self.class.create(person_id: person.id) + person.question_sets << result.id + + result + end def score(answers = nil) if answers.nil? && attributes diff --git a/lib/blockscore/util.rb b/lib/blockscore/util.rb index 6c5cf6e..3624aeb 100644 --- a/lib/blockscore/util.rb +++ b/lib/blockscore/util.rb @@ -11,13 +11,13 @@ module Util } def parse_json!(json_obj) - JSON.parse(json_obj, symbolize_names: true) + JSON.parse(json_obj, :symbolize_names => true) end def parse_json(json_obj) parse_json! json_obj rescue JSON::ParserError - raise Error, 'An error has occurred. If this problem persists, please message support@blockscore.com.' + fail Error, "An error has occurred. If this problem persists, please message support@blockscore.com." end def create_object(resource, options = {}) @@ -65,16 +65,16 @@ def to_constant(camel_cased_word) end def to_camelcase(str) - str.split('_').map(&:capitalize).join('') + str.split('_').map { |i| i.capitalize }.join('') end # Taken from Rulers: http://git.io/vkWqf def to_underscore(str) - str.gsub(/::/, '/') - .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') - .gsub(/([a-z\d])([A-Z])/, '\1_\2') - .tr('-', '_') - .downcase + str.gsub(/::/, '/'). + gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). + gsub(/([a-z\d])([A-Z])/,'\1_\2'). + tr("-", "_"). + downcase end end end diff --git a/lib/blockscore/version.rb b/lib/blockscore/version.rb index 5f17869..26e1366 100644 --- a/lib/blockscore/version.rb +++ b/lib/blockscore/version.rb @@ -1,3 +1,3 @@ module BlockScore - VERSION = '4.2.0'.freeze -end + VERSION = '4.1.2'.freeze +end \ No newline at end of file diff --git a/spec/factories.rb b/spec/factories.rb index c5d8b45..77209c3 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -9,10 +9,10 @@ def initialize delegate :association, to: :@strategy - def result(evaluation, attrs = {}) + def result(evaluation) compiled = @strategy.result(evaluation) case compiled - when BlockScore::Base then compiled.attributes.merge(attrs).to_json + when BlockScore::Base then compiled.attributes.to_json when Hash then compiled.to_json else fail ArgumentError, "don't know how to handle type #{evaluation.class.inspect}" @@ -38,10 +38,6 @@ def full_address "#{street} #{city} #{country}" end -def resource_id - Faker::Number.hexadecimal(24) -end - FactoryGirl.define do # Each response has this metadata so we define it as a trait trait :metadata do @@ -179,29 +175,6 @@ def resource_id details { build(:company_details) } end - factory :fake_member, class: 'BlockScore::FakeResource' do - object { 'fake_member' } - transient do - given_id resource_id - parent_id resource_id - end - - id { given_id } - fake_resource_id { parent_id } - end - - factory :fake_resource, class: 'BlockScore::FakeResource' do - object { 'fake_resource' } - metadata - transient { members_count 2 } - - fake_resources do - members_count.times.map do - resource_id - end - end - end - factory :person_params, class: 'BlockScore::Person' do name document @@ -213,7 +186,6 @@ def resource_id factory :person, class: 'BlockScore::Person' do skip_create - transient { question_sets_count 1 } object { 'person' } metadata @@ -227,20 +199,15 @@ def resource_id address document details { build(:person_details) } - question_sets do - question_sets_count.times.map do - resource_id - end + rand(0..5).times.collect { Faker::Base.regexify(/\d{24}/) } end - - initialize_with { new(attributes) } end # QuestionSet Factory factory :question_set_params, class: 'BlockScore::QuestionSet' do - person_id { resource_id } + person_id { Faker::Base.regexify(/\d{24}/) } end factory :question_set, class: 'BlockScore::QuestionSet' do @@ -250,7 +217,7 @@ def resource_id metadata timestamps testmode - person_id { resource_id } + person_id { Faker::Base.regexify(/\d{24}/) } score { rand * 100 } expired { false } time_limit { rand(120..360) } @@ -336,7 +303,7 @@ def resource_id # We can do this because the error type is determined by the # HTTP response code. factory :blockscore_error, class: Hash, traits: [:resource] do - transient do + ignore do error_type 'api_error' end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index fbfd78a..cab1adf 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,7 +5,6 @@ require 'webmock' require 'webmock/rspec' require 'rspec' -require 'rspec/its' BlockScore::Spec.setup diff --git a/spec/support/stubbed_request.rb b/spec/support/stubbed_request.rb index 4f1428d..ee29519 100644 --- a/spec/support/stubbed_request.rb +++ b/spec/support/stubbed_request.rb @@ -5,12 +5,6 @@ def initialize(request) @uri = request.uri end - def body - JSON.parse(request.body) - rescue - nil - end - def factory_name resource.singularize end diff --git a/spec/support/stubbed_response.rb b/spec/support/stubbed_response.rb index 9bce4dc..61fca05 100644 --- a/spec/support/stubbed_response.rb +++ b/spec/support/stubbed_response.rb @@ -94,7 +94,7 @@ def response private def factory_response - json(factory_name, request.body) + json(factory_name) end end diff --git a/spec/unit/blockscore/actions_spec.rb b/spec/unit/blockscore/actions_spec.rb index c3aa3c7..23d63d7 100644 --- a/spec/unit/blockscore/actions_spec.rb +++ b/spec/unit/blockscore/actions_spec.rb @@ -42,18 +42,8 @@ module BlockScore let(:route) { 'https://api.blockscore.com/fake_resources/abc123' } it 'uses the correct endpoint' do - should receive(:request).with(:get, route, {}).once { resource } - mock.retrieve('abc123').attributes - end - - context 'when id is invalid' do - pending 'should raise not found if not a resource style id' do - expect { mock.retrieve('bad_id') }.to raise_error(NotFoundError) - end - - it 'should raise ArgumentError if empty' do - expect { mock.retrieve('') }.to raise_error(ArgumentError) - end + should receive(:request).with(:get, route, {}).once + mock.retrieve('abc123') end end diff --git a/spec/unit/blockscore/candidate_spec.rb b/spec/unit/blockscore/candidate_spec.rb index bde5e3a..3ef3a2f 100644 --- a/spec/unit/blockscore/candidate_spec.rb +++ b/spec/unit/blockscore/candidate_spec.rb @@ -32,7 +32,7 @@ module BlockScore subject(:search) { -> { candidate.search(constraints) } } context 'search request' do - let(:uri) { '/watchlists' } + let(:uri) { "/watchlists" } let(:body) { { 'candidate_id' => candidate.id }.merge(constraints) } let(:expected) { { body: hash_including(body) } } before { search.call } diff --git a/spec/unit/blockscore/collection_spec.rb b/spec/unit/blockscore/collection_spec.rb deleted file mode 100644 index 1ed9cd0..0000000 --- a/spec/unit/blockscore/collection_spec.rb +++ /dev/null @@ -1,178 +0,0 @@ -module BlockScore - RSpec.describe Collection do - let(:parent) { create(:fake_resource) } - let(:member_class) { FakeResource } - let(:collection) { Collection.new(parent, member_class) } - - before do - Util::PLURAL_LOOKUP['fake_resource'] = 'fake_resources' - allow(member_class).to receive(:create) { create(:fake_member, parent_id: parent.id) } - end - - describe '#all' do - subject { collection.all } - - it 'should return self' do - is_expected.to be(collection) - end - end - - describe '#create' do - let(:created) { create(:fake_member, parent_id: parent.id) } - subject { collection.create } - before(:each) do - allow(member_class).to receive(:create) { created } - end - - it 'should send merged default and arg params' do - foriegn_key = :"#{parent.class.resource}_id" - expect(member_class).to receive(:create).with(foriegn_key => parent.id, foo_param: 'bar_attr') - collection.create(foo_param: 'bar_attr') - end - - it 'should update ids in Parent#attributes' do - expect(parent.attributes[:fake_resources]).to include(subject.id) - end - - it 'should add to collection' do - expect(collection).to include(subject) - end - - it 'should error if parent not created' do - parent = FakeResource.new - collection = Collection.new(parent, member_class) - expect { collection.create }.to raise_error(Error, 'Create parent first') - end - - it 'should retrieve item from registered' do - found_qs = collection.retrieve(subject.id) - expect(subject).to eq(found_qs) - end - end - - describe '#new' do - subject { collection.new } - - it 'should add to collection' do - count = collection.size - result = collection.new - expect(collection.size).to eq(count + 1) - expect(collection).to include(result) - end - - context 'when saving' do - it 'should have parent#id after saving' do - subject.fake_resource_id = 'some_id' - subject.save - expect(subject.fake_resource_id).to eq(parent.id) - end - - it 'should be retrievable after' do - collection.create - subject.save - collection.create - expect(collection.retrieve(subject.id)).to be(subject) - end - end - end - - describe '#retrieve' do - context 'when in person#attributes' do - let(:parent) { create(:fake_resource) } - let(:existing_id) { parent.attributes[:fake_resources].last } - subject { collection.retrieve(existing_id) } - - it 'should retrieve correctly' do - last = collection.last - expect(subject).to eq(last) - expect(subject.id).to eq(existing_id) - end - - it 'checks collect' do - expect(collection).to receive(:each).and_call_original - collection.retrieve(existing_id) - end - end - - context 'when not in person#attributes' do - let(:parent) { create(:fake_resource, members_count: 0) } - let(:collection) { Collection.new(parent, member_class) } - let(:item) { create(:fake_member, parent_id: parent.id) } - let(:data) { parent.attributes.fetch(:fake_resources) } - subject { collection.retrieve(item.id) } - - before(:each) do - allow(member_class).to receive(:retrieve).with(item.id) { item } - end - - it 'uses member_class.retrieve' do - expect(member_class).to receive(:retrieve).with(item.id).and_return(item) - expect(collection.retrieve(item.id)).to eq(item) - end - - it 'registers new question set' do - aggregate_failures('for person and collection') do - expect(collection).to receive(:<<).and_call_original - expect(data).to receive(:<<).with(item.id).and_call_original - end - collection.retrieve(item.id) - end - - it 'errors if not belonging' do - item.fake_resource_id = 'some_not_associated_id' - expect { subject }.to raise_error(Error, 'None belonging') - end - end - end - - describe '#refresh' do - subject { collection } - let(:item) { member_class.create } - before(:each) { parent.attributes[:fake_resources] << item.id } - - # refactor - it 'should register new data from parent' do - parent.attributes[:fake_resources].clear - parent.attributes[:fake_resources].push(item.id) - expect(member_class).to receive(:retrieve).with(item.id).at_least(:twice).and_call_original - subject.refresh - end - - it 'should clear and reload' do - expect(subject).to receive(:clear).and_call_original - expect(subject).to receive(:register_parent_data).and_call_original - result = subject.refresh - expect(subject).to be(result) - end - - context 'when creating' do - it 'should be included in refresh' do - result = subject.create - subject.refresh - expect(subject.map(&:id)).to include(result.id) - end - - it 'should include saved in refresh' do - item = FakeResource.new(fake_resource_id: parent.id) - allow(member_class).to receive(:new) { item } - allow(item).to receive(:save) { create(:fake_member, parent_id: parent.id) } - result = subject.new - result.save - subject.refresh - expect(subject.map(&:id)).to include(result.id) - end - end - - context 'when retrieving belonging' do - it 'should be included in refresh' do - item = create(:fake_resource) - item.parent_id = parent.id - allow(member_class).to receive(:retrieve) { item } - result = subject.retrieve(item.id) - subject.refresh - expect(subject.map(&:id)).to include(result.id) - end - end - end - end -end diff --git a/spec/unit/blockscore/member_spec.rb b/spec/unit/blockscore/member_spec.rb deleted file mode 100644 index 3b88b57..0000000 --- a/spec/unit/blockscore/member_spec.rb +++ /dev/null @@ -1,104 +0,0 @@ -module BlockScore - RSpec.describe Collection::Member do - let(:parent) { create(:fake_resource) } - let(:member_class) { FakeResource } - let(:collection) { Collection.new(parent, member_class) } - - before do - Util::PLURAL_LOOKUP['fake_resource'] = 'fake_resources' - allow(member_class).to receive(:create) { create(:fake_member, parent_id: parent.id) } - end - - context 'when saving' do - let(:member_class) { FakeResource } - let(:parent) { FakeResource.new } - let(:collection) { Collection.new(parent, member_class) } - subject(:member) { collection.new } - - context 'when parent is not persisted' do - before { allow(parent).to receive(:save).and_call_original } - - it { expect(member.save).to be(true) } - - it do - member.save - expect(parent).to have_received(:save).once - end - - context 'after saving' do - before { member.save } - let(:member_parent_id) { member.fake_resource_id } - - it { is_expected.to be_persisted } - it { expect(parent).to be_persisted } - it { expect(member_parent_id).to eql(parent.id) } - end - end - - it 'should not save persisted parent' do - parent.save - - aggregate_failures('when saving') do - expect(parent).not_to receive(:save) - expect(member.save).to be(true) - end - - aggregate_failures('after saving') do - expect(member.persisted?).to be(true) - expect(parent.persisted?).to be(true) - foriegn_key = :"#{parent.class.resource}_id" - expect(member.send(foriegn_key)).to eq(parent.id) - end - end - - it 'should not add to parent if existing' do - member.save - embedded_resource = :"#{Util.to_plural(parent.class.resource)}" - tracked_ids = parent.send(embedded_resource) - size = tracked_ids.size - member.save - expect(size).to eql(size) - expect(tracked_ids).to include(member.id) - end - end - - context 'when created' do - let(:created) { create(:fake_member, parent_id: parent.id) } - subject { collection.create } - before(:each) do - allow(member_class).to receive(:create) { created } - end - - it 'should have the Parent#id' do - expect(member_class).to receive(:create).with(fake_resource_id: parent.id).and_call_original - subject - end - end - - context 'when instantiating a new' do - subject { collection.new } - - it 'should delegate to member_class' do - # odd bug... test fails when replaced with parent.id - args = { fake_resource_id: collection.parent.id } - expect(member_class).to receive(:new).with(args).and_call_original - collection.new - end - - it 'should save parent if not persisted' do - parent = create(:fake_resource) - parent.id = nil - collection = Collection.new(parent, member_class) - item = collection.new - expect(parent).to receive(:save).and_call_original - item.save - end - - it 'should have Parent#id' do - subject.person_id = 'some_id' - subject.save - expect(subject.fake_resource_id).to eq(collection.parent.id) - end - end - end -end diff --git a/spec/unit/blockscore/person_spec.rb b/spec/unit/blockscore/person_spec.rb index a840832..ae72825 100644 --- a/spec/unit/blockscore/person_spec.rb +++ b/spec/unit/blockscore/person_spec.rb @@ -3,30 +3,6 @@ module BlockScore let(:api_stub) { @api_stub } let(:action) { -> { create(:person).details } } - context 'when person has existing question sets' do - let(:person) { create(:person, question_set_count: 1) } - subject(:question_sets) { person.question_sets } - its(:size) { should eql(1) } - its(:ids) { should be(person.attributes[:question_sets]) } - its(:first) { should be_an_instance_of(QuestionSet) } - - it 'should load attributes' do - expect(question_sets.first.attributes).not_to be(nil) - end - end - - it '#persisted?' do - persisted_person = create(:person) - new_person = Person.new - expect(persisted_person.persisted?).to be(true) - expect(new_person.persisted?).to be(false) - end - - it '#id' do - person = create(:person) - expect(person.id).not_to be(nil) - end - it '#valid?' do person = create(:person, status: 'valid') expect(person.valid?).to eq(true) diff --git a/spec/unit/blockscore/question_set_spec.rb b/spec/unit/blockscore/question_set_spec.rb index e2feac6..d498205 100644 --- a/spec/unit/blockscore/question_set_spec.rb +++ b/spec/unit/blockscore/question_set_spec.rb @@ -1,41 +1,61 @@ module BlockScore RSpec.describe QuestionSet do + let(:api_stub) { @api_stub } let(:person) { create(:person_params) } - describe 'api requests' do - let(:api_stub) { @api_stub } - - context 'when creating' do - it 'create' do - person.question_sets.count - person.question_sets.create - assert_requested(api_stub, times: 2) - end - - it 'create question_set count' do - count = person.question_sets.count - person.question_sets.create - expect(count + 1).to be_truthy - assert_requested(api_stub, times: 2) - end + it 'create' do + person.question_sets.count + person.question_sets.create + assert_requested(api_stub, times: 2) + end + + it 'create question_set count' do + count = person.question_sets.count + person.question_sets.create + expect(count + 1).to be_truthy + assert_requested(api_stub, times: 2) + end + + it 'retrieve' do + qs = person.question_sets.create + person.question_sets.retrieve(qs.id) + assert_requested(api_stub, times: 3) + end + + describe '#all' do + it 'requests' do + person.question_sets.all + assert_requested(api_stub, times: 2) + end + + it ':count' do + response = person.question_sets.all(count: 2) + expect(response.count).to eq(2) + assert_requested(api_stub, times: 2) + end + + it ':offset' do + response = person.question_sets.all(count: 2, offset: 2) + expect(response.count).to eq(2) + assert_requested(api_stub, times: 2) + end + end + + describe '#score' do + let(:answers) do + [ + { question_id: 1, answer_id: 1 }, + { question_id: 2, answer_id: 1 }, + { question_id: 3, answer_id: 1 }, + { question_id: 4, answer_id: 1 }, + { question_id: 5, answer_id: 1 } + ] end - context 'when scoring' do - let(:answers) do - [ - { question_id: 1, answer_id: 1 }, - { question_id: 2, answer_id: 1 }, - { question_id: 3, answer_id: 1 }, - { question_id: 4, answer_id: 1 }, - { question_id: 5, answer_id: 1 } - ] - end - - it 'score call does request' do - qs = person.question_sets.create - qs.score(answers) - assert_requested(api_stub, times: 3) - end + it 'score call does request' do + qs = person.question_sets.create + qs.score(answers) + assert_requested(api_stub, times: 3) end end end