From 4bce679c30049bd29d7cf2436f4a65940982a60b Mon Sep 17 00:00:00 2001 From: Chad Shaffer Date: Fri, 30 Jan 2015 11:10:17 -0800 Subject: [PATCH] Adopt rubocop code style --- .rubocop.yml | 1 + .rubocop_todo.yml | 118 ++++ Guardfile | 2 +- Rakefile | 6 +- brainstem.gemspec | 37 +- lib/brainstem.rb | 22 +- lib/brainstem/association_field.rb | 6 +- lib/brainstem/controller_methods.rb | 10 +- lib/brainstem/presenter.rb | 32 +- lib/brainstem/presenter_collection.rb | 47 +- lib/brainstem/time_classes.rb | 2 +- lib/brainstem/version.rb | 2 +- spec/brainstem/controller_methods_spec.rb | 42 +- spec/brainstem/presenter_collection_spec.rb | 727 ++++++++++---------- spec/brainstem/presenter_spec.rb | 162 +++-- spec/brainstem_spec.rb | 20 +- spec/spec_helpers/cleanup.rb | 6 +- spec/spec_helpers/db.rb | 50 +- spec/spec_helpers/presenters.rb | 32 +- 19 files changed, 717 insertions(+), 607 deletions(-) create mode 100644 .rubocop.yml create mode 100644 .rubocop_todo.yml diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..cc32da4b --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1 @@ +inherit_from: .rubocop_todo.yml diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 00000000..ef991d2e --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,118 @@ +# This configuration was generated by `rubocop --auto-gen-config` +# on 2015-01-30 11:07:37 -0800 using RuboCop version 0.28.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 1 +Lint/AmbiguousOperator: + Enabled: false + +# Offense count: 1 +Lint/HandleExceptions: + Enabled: false + +# Offense count: 5 +Lint/ShadowingOuterLocalVariable: + Enabled: false + +# Offense count: 1 +Lint/UselessAccessModifier: + Enabled: false + +# Offense count: 7 +Lint/UselessAssignment: + Enabled: false + +# Offense count: 11 +Metrics/AbcSize: + Max: 90 + +# Offense count: 3 +Metrics/BlockNesting: + Max: 4 + +# Offense count: 2 +# Configuration parameters: CountComments. +Metrics/ClassLength: + Max: 277 + +# Offense count: 6 +Metrics/CyclomaticComplexity: + Max: 15 + +# Offense count: 345 +# Configuration parameters: AllowURI, URISchemes. +Metrics/LineLength: + Max: 274 + +# Offense count: 10 +# Configuration parameters: CountComments. +Metrics/MethodLength: + Max: 51 + +# Offense count: 5 +Metrics/PerceivedComplexity: + Max: 19 + +# Offense count: 1 +Style/AccessorMethodName: + Enabled: false + +# Offense count: 2 +# Configuration parameters: IndentWhenRelativeTo, SupportedStyles, IndentOneStep. +Style/CaseIndentation: + Enabled: false + +# Offense count: 18 +Style/Documentation: + Enabled: false + +# Offense count: 1 +Style/EachWithObject: + Enabled: false + +# Offense count: 1 +Style/EvenOdd: + Enabled: false + +# Offense count: 1 +# Configuration parameters: MinBodyLength. +Style/GuardClause: + Enabled: false + +# Offense count: 1 +# Configuration parameters: MaxLineLength. +Style/IfUnlessModifier: + Enabled: false + +# Offense count: 2 +Style/NestedTernaryOperator: + Enabled: false + +# Offense count: 1 +# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles. +Style/Next: + Enabled: false + +# Offense count: 4 +Style/RegexpLiteral: + MaxSlashes: 0 + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: AllowAsExpressionSeparator. +Style/Semicolon: + Enabled: false + +# Offense count: 1 +# Configuration parameters: Methods. +Style/SingleLineBlockParams: + Enabled: false + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, Whitelist. +Style/TrivialAccessors: + Enabled: false diff --git a/Guardfile b/Guardfile index 808a0094..89f56690 100644 --- a/Guardfile +++ b/Guardfile @@ -4,5 +4,5 @@ guard 'rspec' do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } - watch('spec/spec_helper.rb') { "spec" } + watch('spec/spec_helper.rb') { 'spec' } end diff --git a/Rakefile b/Rakefile index a8a8eb24..2e001252 100755 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,6 @@ #!/usr/bin/env rake -require "bundler/gem_tasks" +require 'bundler/gem_tasks' -require "rspec/core/rake_task" +require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) -task :default => :spec \ No newline at end of file +task default: :spec diff --git a/brainstem.gemspec b/brainstem.gemspec index c2e507c5..e7aed669 100644 --- a/brainstem.gemspec +++ b/brainstem.gemspec @@ -1,28 +1,29 @@ # -*- encoding: utf-8 -*- $LOAD_PATH.unshift File.expand_path('../lib', __FILE__) -require "brainstem/version" +require 'brainstem/version' Gem::Specification.new do |gem| - gem.name = "brainstem" - gem.authors = ["Mavenlink"] - gem.email = ["opensource@mavenlink.com"] - gem.description = %q{Brainstem allows you to create rich API presenters that know how to filter, sort, and include associations.} - gem.summary = %q{ActiveRecord presenters with a rich request API} - gem.homepage = "http://github.com/mavenlink/brainstem" - gem.license = "MIT" + gem.name = 'brainstem' + gem.authors = ['Mavenlink'] + gem.email = ['opensource@mavenlink.com'] + gem.description = 'Brainstem allows you to create rich API presenters that know how to filter, sort, and include associations.' + gem.summary = 'ActiveRecord presenters with a rich request API' + gem.homepage = 'http://github.com/mavenlink/brainstem' + gem.license = 'MIT' - gem.files = Dir["**/*"] - gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } + gem.files = Dir['**/*'] + gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) } gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) - gem.require_paths = ["lib"] + gem.require_paths = ['lib'] gem.version = Brainstem::VERSION - gem.add_dependency "activerecord", ">= 3.2" + gem.add_dependency 'activerecord', '>= 3.2' - gem.add_development_dependency "rake" - gem.add_development_dependency "redcarpet" # for markdown in yard - gem.add_development_dependency "rr" - gem.add_development_dependency "rspec" - gem.add_development_dependency "sqlite3" - gem.add_development_dependency "yard" + gem.add_development_dependency 'rake' + gem.add_development_dependency 'redcarpet' # for markdown in yard + gem.add_development_dependency 'rr' + gem.add_development_dependency 'rspec' + gem.add_development_dependency 'rubocop' + gem.add_development_dependency 'sqlite3' + gem.add_development_dependency 'yard' end diff --git a/lib/brainstem.rb b/lib/brainstem.rb index 5ec0549e..c06f028a 100644 --- a/lib/brainstem.rb +++ b/lib/brainstem.rb @@ -1,21 +1,21 @@ -require "brainstem/version" -require "brainstem/presenter" -require "brainstem/presenter_collection" -require "brainstem/controller_methods" +require 'brainstem/version' +require 'brainstem/presenter' +require 'brainstem/presenter_collection' +require 'brainstem/controller_methods' # The Brainstem module itself contains a +default_namespace+ class attribute and a few helpers that make managing +PresenterCollections+ and their corresponding namespaces easier. module Brainstem # Sets {default_namespace} to a new value. # @param [String] namespace # @return [String] the new default namespace - def self.default_namespace=(namespace) - @default_namespace = namespace + class << self + attr_writer :default_namespace end # The namespace that will be used by {presenter_collection} and {add_presenter_class} if none is given or implied. # @return [String] the default namespace def self.default_namespace - @default_namespace || "none" + @default_namespace || 'none' end # @param [String] namespace @@ -36,7 +36,7 @@ def self.add_presenter_class(presenter_class, *klasses) # @param [Class] klass The Ruby class whose namespace we would like to know. # @return [String] The name of the module containing the passed-in class. def self.namespace_of(klass) - names = klass.to_s.split("::") + names = klass.to_s.split('::') names[-2] ? names[-2] : default_namespace end @@ -46,7 +46,7 @@ def self.logger if defined?(Rails) Rails.logger else - require "logger" + require 'logger' Logger.new(STDOUT) end end @@ -55,7 +55,7 @@ def self.logger # Sets a new Brainstem logger. # @param [Logger] logger A new Brainstem logger. # @return [Logger] The new Brainstem logger. - def self.logger=(logger) - @logger = logger + class << self + attr_writer :logger end end diff --git a/lib/brainstem/association_field.rb b/lib/brainstem/association_field.rb index c1cf807c..403edbdf 100644 --- a/lib/brainstem/association_field.rb +++ b/lib/brainstem/association_field.rb @@ -33,13 +33,13 @@ def initialize(*args, &block) @ignore_type = options[:ignore_type] || false @restrict_to_only = options[:restrict_to_only] || false if block_given? - raise ArgumentError, "options[:json_name] is required when using a block" unless options[:json_name] - raise ArgumentError, "Method name is invalid with a block" if method_name + fail ArgumentError, 'options[:json_name] is required when using a block' unless options[:json_name] + fail ArgumentError, 'Method name is invalid with a block' if method_name @block = block elsif method_name @method_name = method_name else - raise ArgumentError, "Method name or block is required" + fail ArgumentError, 'Method name or block is required' end end diff --git a/lib/brainstem/controller_methods.rb b/lib/brainstem/controller_methods.rb index a04f3b34..e0875442 100644 --- a/lib/brainstem/controller_methods.rb +++ b/lib/brainstem/controller_methods.rb @@ -1,10 +1,8 @@ module Brainstem - # ControllerMethods are intended to be included into controllers that will be handling requests for presented objects. # The present method will pass through +params+, so that any allowed and requested includes, filters, sort orders # will be applied to the presented data. module ControllerMethods - # Return a Ruby hash that contains models requested by the user's params and allowed # by the +name+ presenter's configuration. # @@ -16,7 +14,7 @@ module ControllerMethods # @yield (see PresenterCollection#presenting) # @return (see PresenterCollection#presenting) def present(name, options = {}, &block) - Brainstem.presenter_collection(options[:namespace]).presenting(name, options.reverse_merge(:params => params), &block) + Brainstem.presenter_collection(options[:namespace]).presenting(name, options.reverse_merge(params: params), &block) end # Similar to ControllerMethods#present, but always returns all of the given objects, not just those that match any provided @@ -27,10 +25,10 @@ def present(name, options = {}, &block) # only required if the name cannot be inferred. # @return (see PresenterCollection#presenting) def present_object(objects, options = {}) - options.merge!(:params => params, :apply_default_filters => false) + options.merge!(params: params, apply_default_filters: false) if objects.is_a?(ActiveRecord::Relation) || objects.is_a?(Array) - raise ActiveRecord::RecordNotFound if objects.empty? + fail ActiveRecord::RecordNotFound if objects.empty? klass = objects.first.class ids = objects.map(&:id) else @@ -40,7 +38,7 @@ def present_object(objects, options = {}) end options[:as] = (options[:key_map] || {})[klass.to_s] || klass.table_name - present(klass, options) { klass.where(:id => ids) } + present(klass, options) { klass.where(id: ids) } end alias_method :present_objects, :present_object end diff --git a/lib/brainstem/presenter.rb b/lib/brainstem/presenter.rb index 65202dac..ae11acaf 100644 --- a/lib/brainstem/presenter.rb +++ b/lib/brainstem/presenter.rb @@ -5,7 +5,6 @@ module Brainstem # @abstract Subclass and override {#present} to implement a presenter. class Presenter - # Class methods # Accepts a list of classes this presenter knows how to present. @@ -37,14 +36,14 @@ def self.default_sort_order(sort_string = nil) # Create a named sort order, either containing a string to use as ORDER in a query, or with a block that adds an order Arel predicate to a scope. # @raise [ArgumentError] if neither an order string or block is given. def self.sort_order(name, order = nil, &block) - raise ArgumentError, "A sort order must be given" unless block_given? || order + fail ArgumentError, 'A sort order must be given' unless block_given? || order @sort_orders ||= HashWithIndifferentAccess.new @sort_orders[name] = (block_given? ? block : order) end # @return [Hash] All defined sort orders, keyed by their name. - def self.sort_orders - @sort_orders + class << self + attr_reader :sort_orders end # @overload filter(name, options = {}) @@ -61,16 +60,16 @@ def self.filter(name, options = {}, &block) end # @return [Hash] All defined filters, keyed by their name. - def self.filters - @filters + class << self + attr_reader :filters end def self.search(&block) @search_block = block end - def self.search_block - @search_block + class << self + attr_reader :search_block end # Declares a helper module whose methods will be available in instances of the presenter class and available inside sort and filter blocks. @@ -81,12 +80,11 @@ def self.helper(mod) extend mod end - # Instance methods # @raise [RuntimeError] if this method has not been overridden in the presenter subclass. - def present(model) - raise "Please override #present(model) in your subclass of Brainstem::Presenter" + def present(_model) + fail 'Please override #present(model) in your subclass of Brainstem::Presenter' end # @api private @@ -124,7 +122,7 @@ def group_present(models, associations = []) end # Subclasses can define this if they wish. This method will be called before {#present}. - def custom_preload(models, associations = []) + def custom_preload(_models, _associations = []) end # @api private @@ -135,7 +133,7 @@ def datetimes_to_json(struct) struct.map { |value| datetimes_to_json(value) } when Hash processed = {} - struct.each { |k,v| processed[k] = datetimes_to_json(v) } + struct.each { |k, v| processed[k] = datetimes_to_json(v) } processed when Date struct.strftime('%F') @@ -155,14 +153,14 @@ def load_associations!(model, struct, associations) struct.delete key id_attr = value.method_name ? "#{value.method_name}_id" : nil - if id_attr && model.class.columns_hash.has_key?(id_attr) + if id_attr && model.class.columns_hash.key?(id_attr) reflection = value.method_name && reflections[value.method_name.to_s] if reflection && reflection.options[:polymorphic] && !value.ignore_type struct["#{key.to_s.singularize}_ref".to_sym] = begin if (id_attr = model.send(id_attr)).present? { - :id => to_s_except_nil(id_attr), - :key => model.send("#{value.method_name}_type").try(:constantize).try(:table_name) + id: to_s_except_nil(id_attr), + key: model.send("#{value.method_name}_type").try(:constantize).try(:table_name) } end end @@ -172,7 +170,7 @@ def load_associations!(model, struct, associations) elsif associations.include?(key.to_s) result = value.call(model) if result.is_a?(Array) || result.is_a?(ActiveRecord::Relation) - struct["#{key.to_s.singularize}_ids".to_sym] = result.map {|a| to_s_except_nil(a.is_a?(ActiveRecord::Base) ? a.id : a) } + struct["#{key.to_s.singularize}_ids".to_sym] = result.map { |a| to_s_except_nil(a.is_a?(ActiveRecord::Base) ? a.id : a) } else if result.is_a?(ActiveRecord::Base) struct["#{key.to_s.singularize}_id".to_sym] = to_s_except_nil(result.id) diff --git a/lib/brainstem/presenter_collection.rb b/lib/brainstem/presenter_collection.rb index 9801d38c..16f513dc 100644 --- a/lib/brainstem/presenter_collection.rb +++ b/lib/brainstem/presenter_collection.rb @@ -3,7 +3,6 @@ module Brainstem class PresenterCollection - # @!attribute default_max_per_page # @return [Integer] The maximum number of objects that can be requested in a single presented hash. attr_accessor :default_max_per_page @@ -78,7 +77,7 @@ def presenting(name, options = {}, &block) # Determine if an exception should be raised on an empty result set. if options[:raise_on_empty] && records.empty? - raise options[:empty_error_class] || ActiveRecord::RecordNotFound + fail options[:empty_error_class] || ActiveRecord::RecordNotFound end records = order_for_search(records, ordered_search_ids) if searching? options @@ -94,7 +93,7 @@ def presenting(name, options = {}, &block) if models.length > 0 presenter = for!(models.first.class) - assoc = includes_hash.to_a.find { |k, v| v.json_name == json_name } + assoc = includes_hash.to_a.find { |_k, v| v.json_name == json_name } struct[json_name] = presenter.group_present(models, []) else struct[json_name] = [] @@ -104,7 +103,7 @@ def presenting(name, options = {}, &block) if primary_models.length > 0 presented_primary_models = options[:presenter].group_present(models, includes_hash.keys) struct[options[:as]] += presented_primary_models - struct[:results] = presented_primary_models.map { |model| { :key => options[:as].to_s, :id => model[:id] } } + struct[:results] = presented_primary_models.map { |model| { key: options[:as].to_s, id: model[:id] } } end rewrite_keys_as_objects!(struct) @@ -133,7 +132,7 @@ def for(klass) # @return [Brainstem::Presenter] The presenter that knows how to present the class +klass+. # @raise [ArgumentError] if there is no known presenter for +klass+. def for!(klass) - self.for(klass) || raise(ArgumentError, "Unable to find a presenter for class #{klass}") + self.for(klass) || fail(ArgumentError, "Unable to find a presenter for class #{klass}") end private @@ -185,7 +184,7 @@ def calculate_allowed_includes(presenter, presented_class, is_only_query) if association && !association.options[:polymorphic] v.json_name = association && association.table_name.to_sym if v.json_name.nil? - raise ":json_name is a required option for method-based associations (#{presented_class}##{v.method_name})" + fail ":json_name is a required option for method-based associations (#{presented_class}##{v.method_name})" end end end @@ -207,8 +206,8 @@ def filter_includes(user_includes, allowed_includes) end def handle_only(scope, only) - ids = (only || "").split(",").select {|id| id =~ /\A\d+\Z/}.uniq - [scope.where(:id => ids), scope.where(:id => ids).count] + ids = (only || '').split(',').select { |id| id =~ /\A\d+\Z/ }.uniq + [scope.where(id: ids), scope.where(id: ids).count] end def run_filters(scope, options) @@ -233,7 +232,7 @@ def extract_filters(options) (options[:presenter].filters || {}).each do |filter_name, filter| requested = options[:params][filter_name] requested = requested.is_a?(Array) ? requested : (requested.present? ? requested.to_s : nil) - requested = requested == "true" ? true : (requested == "false" ? false : requested) + requested = requested == 'true' ? true : (requested == 'false' ? false : requested) filter_options = filter[0] args = run_defaults && requested.nil? ? filter_options[:default] : requested @@ -250,8 +249,8 @@ def run_search(scope, includes, sort_name, direction, options) return scope unless searching? options search_options = HashWithIndifferentAccess.new( - :include => includes, - :order => { :sort_order => sort_name, :direction => direction }, + include: includes, + order: { sort_order: sort_name, direction: direction } ) if options[:params][:limit].present? && options[:params][:offset].present? @@ -266,9 +265,9 @@ def run_search(scope, includes, sort_name, direction, options) result_ids, count = options[:presenter].search_block.call(options[:params][:search], search_options) if result_ids - [scope.where(:id => result_ids ), count, result_ids] + [scope.where(id: result_ids), count, result_ids] else - raise(SearchUnavailableError, 'Search is currently unavailable') + fail(SearchUnavailableError, 'Search is currently unavailable') end end @@ -300,7 +299,7 @@ def handle_ordering(scope, options) when nil scope else - scope.order(order.to_s + " " + direction) + scope.order(order.to_s + ' ' + direction) end end @@ -313,8 +312,8 @@ def calculate_order_and_direction(options) end def calculate_sort_name_and_direction(options) - default_column, default_direction = (options[:presenter].default_sort_order || "updated_at:desc").split(":") - sort_name, direction = (options[:params][:order] || "").split(":") + default_column, default_direction = (options[:presenter].default_sort_order || 'updated_at:desc').split(':') + sort_name, direction = (options[:params][:order] || '').split(':') sort_orders = options[:presenter].sort_orders || {} unless sort_name.present? && sort_orders[sort_name] sort_name = default_column @@ -326,14 +325,14 @@ def calculate_sort_name_and_direction(options) def perform_preloading(records, includes_hash) records.tap do |models| - association_names_to_preload = includes_hash.values.map {|i| i.method_name } + association_names_to_preload = includes_hash.values.map(&:method_name) if models.first reflections = Brainstem::PresenterCollection.reflections(models.first.class) - association_names_to_preload.reject! { |association| !reflections.has_key?(association.to_s) } + association_names_to_preload.reject! { |association| !reflections.key?(association.to_s) } end if association_names_to_preload.any? Brainstem::PresenterCollection.preload(models, association_names_to_preload) - Brainstem.logger.info "Eager loaded #{association_names_to_preload.join(", ")}." + Brainstem.logger.info "Eager loaded #{association_names_to_preload.join(', ')}." end end end @@ -342,14 +341,14 @@ def gather_associations(models, includes_hash) record_hash = {} primary_models = [] - includes_hash.each do |include, include_data| + includes_hash.each do |_include, include_data| record_hash[include_data.json_name] ||= [] if include_data.json_name end models.each do |model| primary_models << model - includes_hash.each do |include, include_data| + includes_hash.each do |_include, include_data| models = Array(include_data.call(model)) if include_data.json_name @@ -370,14 +369,14 @@ def gather_associations(models, includes_hash) def rewrite_keys_as_objects!(struct) (struct.keys - [:count, :results]).each do |key| - struct[key] = struct[key].inject({}) {|memo, obj| memo[obj[:id] || obj["id"] || "unknown_id"] = obj; memo } + struct[key] = struct[key].inject({}) { |memo, obj| memo[obj[:id] || obj['id'] || 'unknown_id'] = obj; memo } end end def set_default_filters_option!(options) - return unless options[:params].has_key?(:apply_default_filters) + return unless options[:params].key?(:apply_default_filters) - options[:apply_default_filters] = [true, "true", "TRUE", 1, "1"].include? options[:params].delete(:apply_default_filters) + options[:apply_default_filters] = [true, 'true', 'TRUE', 1, '1'].include? options[:params].delete(:apply_default_filters) end # Class Methods diff --git a/lib/brainstem/time_classes.rb b/lib/brainstem/time_classes.rb index af5f2265..86d94a83 100644 --- a/lib/brainstem/time_classes.rb +++ b/lib/brainstem/time_classes.rb @@ -11,4 +11,4 @@ class Presenter rescue LoadError end end -end \ No newline at end of file +end diff --git a/lib/brainstem/version.rb b/lib/brainstem/version.rb index 35cfc8ff..f3d583d4 100644 --- a/lib/brainstem/version.rb +++ b/lib/brainstem/version.rb @@ -1,3 +1,3 @@ module Brainstem - VERSION = "0.2.6.1" + VERSION = '0.2.6.1' end diff --git a/spec/brainstem/controller_methods_spec.rb b/spec/brainstem/controller_methods_spec.rb index 30da3af6..212c8a1c 100644 --- a/spec/brainstem/controller_methods_spec.rb +++ b/spec/brainstem/controller_methods_spec.rb @@ -8,7 +8,7 @@ class FakeController attr_accessor :call_results def params - { :a => :b } + { a: :b } end end @@ -19,65 +19,65 @@ def params PostPresenter.presents Post end - describe "#present_object" do + describe '#present_object' do before do @controller = FakeController.new end - describe "calling #present with sensible params" do + describe 'calling #present with sensible params' do before do def @controller.present(klass, options) - @call_results = { :klass => klass, :options => options, :block_result => yield } + @call_results = { klass: klass, options: options, block_result: yield } end end - it "works with arrays of ActiveRecord objects" do + it 'works with arrays of ActiveRecord objects' do @controller.present_object([Workspace.find(1), Workspace.find(3)]) expect(@controller.call_results[:klass]).to eq(Workspace) - expect(@controller.call_results[:options][:as]).to eq("workspaces") + expect(@controller.call_results[:options][:as]).to eq('workspaces') expect(@controller.call_results[:block_result].pluck(:id)).to eq([1, 3]) end - it "works with a Relation" do + it 'works with a Relation' do @controller.present_object(Workspace.owned_by(1)) expect(@controller.call_results[:klass]).to eq(Workspace) - expect(@controller.call_results[:options][:as]).to eq("workspaces") + expect(@controller.call_results[:options][:as]).to eq('workspaces') expect(@controller.call_results[:block_result].pluck(:id)).to eq([1, 2, 3, 4]) end - it "works with singleton objects" do + it 'works with singleton objects' do @controller.present_object(Workspace.find(1)) expect(@controller.call_results[:klass]).to eq(Workspace) - expect(@controller.call_results[:options][:as]).to eq("workspaces") + expect(@controller.call_results[:options][:as]).to eq('workspaces') expect(@controller.call_results[:block_result].pluck(:id)).to eq([1]) end - it "accepts a key map" do - @controller.present_object(Workspace.find(1), :key_map => { "Workspace" => "your_workspaces" }) + it 'accepts a key map' do + @controller.present_object(Workspace.find(1), key_map: { 'Workspace' => 'your_workspaces' }) expect(@controller.call_results[:klass]).to eq(Workspace) - expect(@controller.call_results[:options][:as]).to eq("your_workspaces") + expect(@controller.call_results[:options][:as]).to eq('your_workspaces') expect(@controller.call_results[:block_result].pluck(:id)).to eq([1]) end - it "passes through the controller params" do - @controller.present_object(Workspace.find(1), :key_map => { "Workspace" => "your_workspaces" }) - expect(@controller.call_results[:options][:params]).to eq(@controller.params.merge(:only => '1')) + it 'passes through the controller params' do + @controller.present_object(Workspace.find(1), key_map: { 'Workspace' => 'your_workspaces' }) + expect(@controller.call_results[:options][:params]).to eq(@controller.params.merge(only: '1')) end - it "passes through supplied options" do - @controller.present_object(Workspace.find(1), :foo => :bar) + it 'passes through supplied options' do + @controller.present_object(Workspace.find(1), foo: :bar) expect(@controller.call_results[:options][:foo]).to eq(:bar) end - it "adds an only param if there is only one object to present" do + it 'adds an only param if there is only one object to present' do @controller.present_object(Workspace.find(1)) - expect(@controller.call_results[:options][:params][:only]).to eq("1") + expect(@controller.call_results[:options][:params][:only]).to eq('1') @controller.present_object(Workspace.all) expect(@controller.call_results[:options][:params][:only]).to be_nil end - it "passes :apply_default_filters => false to the PresenterCollection so that filters are not applied by default" do + it 'passes :apply_default_filters => false to the PresenterCollection so that filters are not applied by default' do @controller.present_object(Workspace.find(1)) expect(@controller.call_results[:options][:apply_default_filters]).to eq(false) end diff --git a/spec/brainstem/presenter_collection_spec.rb b/spec/brainstem/presenter_collection_spec.rb index 49850c7f..eeb16ab0 100644 --- a/spec/brainstem/presenter_collection_spec.rb +++ b/spec/brainstem/presenter_collection_spec.rb @@ -10,299 +10,299 @@ @presenter_collection = Brainstem.presenter_collection end - let(:bob) { User.where(:username => "bob").first } + let(:bob) { User.where(username: 'bob').first } let(:bob_workspaces_ids) { bob.workspaces.map(&:id) } - let(:jane) { User.where(:username => "jane").first } + let(:jane) { User.where(username: 'jane').first } - describe "#presenting" do - describe "#pagination" do + describe '#presenting' do + describe '#pagination' do before do @presenter_collection.default_per_page = 2 @presenter_collection.default_max_per_page = 3 end - it "has a global per_page default" do - expect(@presenter_collection.presenting("workspaces") { Workspace.order('id desc') }[:workspaces].length).to eq(2) + it 'has a global per_page default' do + expect(@presenter_collection.presenting('workspaces') { Workspace.order('id desc') }[:workspaces].length).to eq(2) end - it "will not accept a per_page less than 1" do - expect(@presenter_collection.presenting("workspaces", :params => { :per_page => 0 }) { Workspace.order('id desc') }[:workspaces].length).to eq(2) - expect(@presenter_collection.presenting("workspaces", :per_page => 0) { Workspace.order('id desc') }[:workspaces].length).to eq(2) + it 'will not accept a per_page less than 1' do + expect(@presenter_collection.presenting('workspaces', params: { per_page: 0 }) { Workspace.order('id desc') }[:workspaces].length).to eq(2) + expect(@presenter_collection.presenting('workspaces', per_page: 0) { Workspace.order('id desc') }[:workspaces].length).to eq(2) end - it "will accept strings" do - struct = @presenter_collection.presenting("workspaces", :params => { :per_page => "1", :page => "2" }) { Workspace.order('id desc') } + it 'will accept strings' do + struct = @presenter_collection.presenting('workspaces', params: { per_page: '1', page: '2' }) { Workspace.order('id desc') } expect(struct[:results].first[:id]).to eq(Workspace.order('id desc')[1].id.to_s) end - it "has a global max_per_page default" do - expect(@presenter_collection.presenting("workspaces", :params => { :per_page => 5 }) { Workspace.order('id desc') }[:workspaces].length).to eq(3) + it 'has a global max_per_page default' do + expect(@presenter_collection.presenting('workspaces', params: { per_page: 5 }) { Workspace.order('id desc') }[:workspaces].length).to eq(3) end - it "takes a configurable default page size and max page size" do - expect(@presenter_collection.presenting("workspaces", :params => { :per_page => 5 }, :max_per_page => 4) { Workspace.order('id desc') }[:workspaces].length).to eq(4) + it 'takes a configurable default page size and max page size' do + expect(@presenter_collection.presenting('workspaces', params: { per_page: 5 }, max_per_page: 4) { Workspace.order('id desc') }[:workspaces].length).to eq(4) end - describe "limits and offsets" do - context "when only per_page and page are present" do + describe 'limits and offsets' do + context 'when only per_page and page are present' do it "honors the user's requested page size and page and returns counts" do - result = @presenter_collection.presenting("workspaces", :params => { :per_page => 1, :page => 2 }) { Workspace.order('id desc') }[:results] + result = @presenter_collection.presenting('workspaces', params: { per_page: 1, page: 2 }) { Workspace.order('id desc') }[:results] expect(result.length).to eq(1) expect(result.first[:id]).to eq(Workspace.order('id desc')[1].id.to_s) - result = @presenter_collection.presenting("workspaces", :params => { :per_page => 2, :page => 2 }) { Workspace.order('id desc') }[:results] + result = @presenter_collection.presenting('workspaces', params: { per_page: 2, page: 2 }) { Workspace.order('id desc') }[:results] expect(result.length).to eq(2) expect(result.map { |m| m[:id] }).to eq(Workspace.order('id desc')[2..3].map(&:id).map(&:to_s)) end - it "defaults to 1 if the page number is less than 1" do - result = @presenter_collection.presenting("workspaces", :params => { :per_page => 1, :page => 0 }) { Workspace.order('id desc') }[:results] + it 'defaults to 1 if the page number is less than 1' do + result = @presenter_collection.presenting('workspaces', params: { per_page: 1, page: 0 }) { Workspace.order('id desc') }[:results] expect(result.length).to eq(1) expect(result.first[:id]).to eq(Workspace.order('id desc')[0].id.to_s) end end - context "when only limit and offset are present" do + context 'when only limit and offset are present' do it "honors the user's requested limit and offset and returns counts" do - result = @presenter_collection.presenting("workspaces", :params => { :limit => 1, :offset => 2 }) { Workspace.order('id desc') }[:results] + result = @presenter_collection.presenting('workspaces', params: { limit: 1, offset: 2 }) { Workspace.order('id desc') }[:results] expect(result.length).to eq(1) expect(result.first[:id]).to eq(Workspace.order('id desc')[2].id.to_s) - result = @presenter_collection.presenting("workspaces", :params => { :limit => 2, :offset => 2 }) { Workspace.order('id desc') }[:results] + result = @presenter_collection.presenting('workspaces', params: { limit: 2, offset: 2 }) { Workspace.order('id desc') }[:results] expect(result.length).to eq(2) expect(result.map { |m| m[:id] }).to eq(Workspace.order('id desc')[2..3].map(&:id).map(&:to_s)) end - it "defaults to offset 0 if the passed offset is less than 0 and limit to 1 if the passed limit is less than 1" do + it 'defaults to offset 0 if the passed offset is less than 0 and limit to 1 if the passed limit is less than 1' do stub.proxy(@presenter_collection).calculate_offset(anything).times(1) stub.proxy(@presenter_collection).calculate_limit(anything).times(1) - result = @presenter_collection.presenting("workspaces", :params => { :limit => -1, :offset => -1 }) { Workspace.order('id desc') }[:results] + result = @presenter_collection.presenting('workspaces', params: { limit: -1, offset: -1 }) { Workspace.order('id desc') }[:results] expect(result.length).to eq(1) expect(result.first[:id]).to eq(Workspace.order('id desc')[0].id.to_s) end end - context "when both sets of params are present" do - it "prefers limit and offset over per_page and page" do - result = @presenter_collection.presenting("workspaces", :params => { :limit => 1, :offset => 0, :per_page => 2, :page => 2 }) { Workspace.order('id desc') }[:results] + context 'when both sets of params are present' do + it 'prefers limit and offset over per_page and page' do + result = @presenter_collection.presenting('workspaces', params: { limit: 1, offset: 0, per_page: 2, page: 2 }) { Workspace.order('id desc') }[:results] expect(result.length).to eq(1) expect(result.first[:id]).to eq(Workspace.order('id desc')[0].id.to_s) end - it "uses per_page and page if limit and offset are not complete" do - result = @presenter_collection.presenting("workspaces", :params => { :limit => 5, :per_page => 1, :page => 0 }) { Workspace.order('id desc') }[:results] + it 'uses per_page and page if limit and offset are not complete' do + result = @presenter_collection.presenting('workspaces', params: { limit: 5, per_page: 1, page: 0 }) { Workspace.order('id desc') }[:results] expect(result.length).to eq(1) expect(result.first[:id]).to eq(Workspace.order('id desc')[0].id.to_s) - result = @presenter_collection.presenting("workspaces", :params => { :offset => 5, :per_page => 1, :page => 0 }) { Workspace.order('id desc') }[:results] + result = @presenter_collection.presenting('workspaces', params: { offset: 5, per_page: 1, page: 0 }) { Workspace.order('id desc') }[:results] expect(result.length).to eq(1) expect(result.first[:id]).to eq(Workspace.order('id desc')[0].id.to_s) end end end - describe "raise_on_empty option" do - context "raise_on_empty is true" do - context "results are empty" do - it "should raise the provided error class when the empty_error_class option is provided" do + describe 'raise_on_empty option' do + context 'raise_on_empty is true' do + context 'results are empty' do + it 'should raise the provided error class when the empty_error_class option is provided' do class MyException < Exception; end - expect { - @presenter_collection.presenting("workspaces", :raise_on_empty => true, :empty_error_class => MyException) { Workspace.where(:id => nil) } - }.to raise_error(MyException) + expect do + @presenter_collection.presenting('workspaces', raise_on_empty: true, empty_error_class: MyException) { Workspace.where(id: nil) } + end.to raise_error(MyException) end - it "should raise ActiveRecord::RecordNotFound when the empty_error_class option is not provided" do - expect { - @presenter_collection.presenting("workspaces", :raise_on_empty => true) { Workspace.where(:id => nil) } - }.to raise_error(ActiveRecord::RecordNotFound) + it 'should raise ActiveRecord::RecordNotFound when the empty_error_class option is not provided' do + expect do + @presenter_collection.presenting('workspaces', raise_on_empty: true) { Workspace.where(id: nil) } + end.to raise_error(ActiveRecord::RecordNotFound) end end - context "results are not empty" do - it "should not raise an exception" do + context 'results are not empty' do + it 'should not raise an exception' do expect(Workspace.count).to be > 0 - expect { - @presenter_collection.presenting("workspaces", :raise_on_empty => true) { Workspace.order('id desc') } - }.not_to raise_error + expect do + @presenter_collection.presenting('workspaces', raise_on_empty: true) { Workspace.order('id desc') } + end.not_to raise_error end end end - context "raise_on_empty is false" do - it "should not raise an exception when the results are empty" do - expect { - @presenter_collection.presenting("workspaces") { Workspace.where(:id => nil) } - }.not_to raise_error + context 'raise_on_empty is false' do + it 'should not raise an exception when the results are empty' do + expect do + @presenter_collection.presenting('workspaces') { Workspace.where(id: nil) } + end.not_to raise_error end end end - describe "counts" do + describe 'counts' do before do @presenter_collection.default_per_page = 500 @presenter_collection.default_max_per_page = 500 end - it "returns the unique count by model id" do - result = @presenter_collection.presenting("workspaces", :params => { :per_page => 2, :page => 1 }) { Workspace.order('id desc') } + it 'returns the unique count by model id' do + result = @presenter_collection.presenting('workspaces', params: { per_page: 2, page: 1 }) { Workspace.order('id desc') } expect(result[:count]).to eq(Workspace.count) end end end - describe "uses presenters" do - it "finds presenter by table name string" do - result = @presenter_collection.presenting("workspaces") { Workspace.order('id desc') } + describe 'uses presenters' do + it 'finds presenter by table name string' do + result = @presenter_collection.presenting('workspaces') { Workspace.order('id desc') } expect(result[:workspaces].length).to eq(Workspace.count) end - it "finds presenter by model name string" do - result = @presenter_collection.presenting("Workspace") { order('id desc') } + it 'finds presenter by model name string' do + result = @presenter_collection.presenting('Workspace') { order('id desc') } expect(result[:workspaces].length).to eq(Workspace.count) end - it "finds presenter by model" do + it 'finds presenter by model' do result = @presenter_collection.presenting(Workspace) { order('id desc') } expect(result[:workspaces].length).to eq(Workspace.count) end - it "infers the table name from the model" do - result = @presenter_collection.presenting("not_workspaces", :model => "Workspace", :params => { :per_page => 2, :page => 1 }) { Workspace.order('id desc') } + it 'infers the table name from the model' do + result = @presenter_collection.presenting('not_workspaces', model: 'Workspace', params: { per_page: 2, page: 1 }) { Workspace.order('id desc') } expect(result[:not_workspaces]).not_to be_empty expect(result[:count]).to eq(Workspace.count) end end describe "the 'results' top level key" do - it "comes back with an explicit list of the matching results" do - structure = @presenter_collection.presenting("workspaces", :params => { :include => "tasks" }, :max_per_page => 2) { Workspace.where(:id => 1) } + it 'comes back with an explicit list of the matching results' do + structure = @presenter_collection.presenting('workspaces', params: { include: 'tasks' }, max_per_page: 2) { Workspace.where(id: 1) } expect(structure.keys).to match_array([:workspaces, :tasks, :count, :results]) - expect(structure[:results]).to eq(Workspace.where(:id => 1).limit(2).map {|w| { :key => "workspaces", :id => w.id.to_s } }) - expect(structure[:workspaces].keys).to eq(%w[1]) + expect(structure[:results]).to eq(Workspace.where(id: 1).limit(2).map { |w| { key: 'workspaces', id: w.id.to_s } }) + expect(structure[:workspaces].keys).to eq(%w(1)) end end - describe "includes" do - it "reads allowed includes from the presenter" do - result = @presenter_collection.presenting("workspaces", :params => { :include => "drop table,tasks,users" }) { Workspace.order('id desc') } + describe 'includes' do + it 'reads allowed includes from the presenter' do + result = @presenter_collection.presenting('workspaces', params: { include: 'drop table,tasks,users' }) { Workspace.order('id desc') } expect(result.keys).to match_array([:count, :workspaces, :tasks, :results]) - result = @presenter_collection.presenting("workspaces", :params => { :include => "foo,tasks,lead_user" }) { Workspace.order('id desc') } + result = @presenter_collection.presenting('workspaces', params: { include: 'foo,tasks,lead_user' }) { Workspace.order('id desc') } expect(result.keys).to match_array([:count, :workspaces, :tasks, :users, :results]) end - it "allows the allowed includes list to have different json names and association names" do - result = @presenter_collection.presenting("tasks", - :params => { :include => "other_tasks" }) { Task.order('id desc') } + it 'allows the allowed includes list to have different json names and association names' do + result = @presenter_collection.presenting('tasks', + params: { include: 'other_tasks' }) { Task.order('id desc') } expect(result[:tasks]).to be_present expect(result[:other_tasks]).to be_present end - it "defaults to not include any allowed includes" do + it 'defaults to not include any allowed includes' do tasked_workspace = Task.first - result = @presenter_collection.presenting("workspaces", :max_per_page => 2) { Workspace.where(:id => tasked_workspace.workspace_id) } - expect(result[:workspaces].keys).to eq([ tasked_workspace.workspace_id.to_s ]) + result = @presenter_collection.presenting('workspaces', max_per_page: 2) { Workspace.where(id: tasked_workspace.workspace_id) } + expect(result[:workspaces].keys).to eq([tasked_workspace.workspace_id.to_s]) expect(result[:tasks]).to be_nil end - it "loads has_many associations and returns them when requested" do - result = @presenter_collection.presenting("workspaces", :params => { :include => "tasks" }, :max_per_page => 2) { Workspace.where(:id => 1) } + it 'loads has_many associations and returns them when requested' do + result = @presenter_collection.presenting('workspaces', params: { include: 'tasks' }, max_per_page: 2) { Workspace.where(id: 1) } expect(result[:tasks].keys).to match_array(Workspace.first.tasks.map(&:id).map(&:to_s)) - expect(result[:workspaces]["1"][:task_ids]).to match_array(Workspace.first.tasks.map(&:id).map(&:to_s)) + expect(result[:workspaces]['1'][:task_ids]).to match_array(Workspace.first.tasks.map(&:id).map(&:to_s)) end - it "returns appropriate fields" do - result = @presenter_collection.presenting("workspaces", - :params => { :include => "tasks" }, - :max_per_page => 2) { Workspace.where(:id => 1) } + it 'returns appropriate fields' do + result = @presenter_collection.presenting('workspaces', + params: { include: 'tasks' }, + max_per_page: 2) { Workspace.where(id: 1) } expect(result[:workspaces].values.first).to have_key(:description) expect(result[:tasks].values.first).to have_key(:name) end - it "loads belongs_tos and returns them when requested" do - result = @presenter_collection.presenting("tasks", :params => { :include => "workspace" }, :max_per_page => 2) { Task.where(:id => 1) } - expect(result[:workspaces].keys).to eq(%w[1]) + it 'loads belongs_tos and returns them when requested' do + result = @presenter_collection.presenting('tasks', params: { include: 'workspace' }, max_per_page: 2) { Task.where(id: 1) } + expect(result[:workspaces].keys).to eq(%w(1)) end it "doesn't return nils when belong_tos are missing" do t = Task.first t.update_attribute :workspace, nil expect(t.reload.workspace).to be_nil - result = @presenter_collection.presenting("tasks", :params => { :include => "workspace" }, :max_per_page => 2) { Task.where(:id => t.id) } - expect(result[:tasks].keys).to eq([ t.id.to_s ]) + result = @presenter_collection.presenting('tasks', params: { include: 'workspace' }, max_per_page: 2) { Task.where(id: t.id) } + expect(result[:tasks].keys).to eq([t.id.to_s]) expect(result[:workspaces]).to eq({}) expect(result.keys).to match_array([:tasks, :workspaces, :count, :results]) end - it "returns sensible data when including something of the same type as the primary model" do - result = @presenter_collection.presenting("tasks", :params => { :include => "sub_tasks" }) { Task.where(:id => 2) } + it 'returns sensible data when including something of the same type as the primary model' do + result = @presenter_collection.presenting('tasks', params: { include: 'sub_tasks' }) { Task.where(id: 2) } sub_task_ids = Task.find(2).sub_tasks.map(&:id).map(&:to_s) - expect(result[:tasks].keys).to match_array(sub_task_ids + ["2"]) - expect(result[:tasks]["2"][:sub_task_ids]).to eq(sub_task_ids) # The primary should have a sub_story_ids array. + expect(result[:tasks].keys).to match_array(sub_task_ids + ['2']) + expect(result[:tasks]['2'][:sub_task_ids]).to eq(sub_task_ids) # The primary should have a sub_story_ids array. expect(result[:tasks][sub_task_ids.first][:sub_task_ids]).not_to be_present # Sub stories should not have a sub_story_ids array. end - it "includes requested includes even when all records are filtered" do - result = @presenter_collection.presenting("workspaces", :params => { :only => "not an id", :include => "not an include,tasks" }) { Workspace.order("id desc") } + it 'includes requested includes even when all records are filtered' do + result = @presenter_collection.presenting('workspaces', params: { only: 'not an id', include: 'not an include,tasks' }) { Workspace.order('id desc') } expect(result[:workspaces].length).to eq(0) expect(result[:tasks].length).to eq(0) end - it "includes requested includes even when the scope has no records" do - expect(Workspace.where(:id => 123456789)).to be_empty - result = @presenter_collection.presenting("workspaces", :params => { :include => "not an include,tasks" }) { Workspace.where(:id => 123456789) } + it 'includes requested includes even when the scope has no records' do + expect(Workspace.where(id: 123_456_789)).to be_empty + result = @presenter_collection.presenting('workspaces', params: { include: 'not an include,tasks' }) { Workspace.where(id: 123_456_789) } expect(result[:workspaces].length).to eq(0) expect(result[:tasks].length).to eq(0) end - it "preloads associations when they are full model-level associations" do + it 'preloads associations when they are full model-level associations' do # Here, primary_maven is a method on Workspace, not a true association. mock(Brainstem::PresenterCollection).preload(anything, [:tasks]) - result = @presenter_collection.presenting("workspaces", :params => { :include => "tasks" }) { Workspace.order('id desc') } + result = @presenter_collection.presenting('workspaces', params: { include: 'tasks' }) { Workspace.order('id desc') } expect(result[:tasks].length).to be > 0 end - it "works with model methods that load records (but without preloading)" do - result = @presenter_collection.presenting("workspaces", :params => { :include => "lead_user" }) { Workspace.order('id desc') } + it 'works with model methods that load records (but without preloading)' do + result = @presenter_collection.presenting('workspaces', params: { include: 'lead_user' }) { Workspace.order('id desc') } expect(result[:workspaces][Workspace.first.id.to_s]).to be_present expect(result[:users][Workspace.first.lead_user.id.to_s]).to be_present end - it "can accept a lambda for the association and uses that when present" do - result = @presenter_collection.presenting("users", :params => { :include => "odd_workspaces" }) { User.where(:id => 1) } + it 'can accept a lambda for the association and uses that when present' do + result = @presenter_collection.presenting('users', params: { include: 'odd_workspaces' }) { User.where(id: 1) } expect(result[:odd_workspaces][Workspace.first.id.to_s]).to be_present expect(result[:users][Workspace.first.lead_user.id.to_s]).to be_present end - describe "restricted associations" do - it "does apply includes that are restricted to only queries in an only query" do + describe 'restricted associations' do + it 'does apply includes that are restricted to only queries in an only query' do t = Task.first - result = @presenter_collection.presenting("tasks", :params => { :include => "restricted", :only => t.id.to_s }, :max_per_page => 2) { Task.where(:id => t.id) } + result = @presenter_collection.presenting('tasks', params: { include: 'restricted', only: t.id.to_s }, max_per_page: 2) { Task.where(id: t.id) } expect(result[:tasks][t.id.to_s].keys).to include(:restricted_id) expect(result.keys).to include(:restricted_associations) end - it "does not apply includes that are restricted to only queries in a non-only query" do + it 'does not apply includes that are restricted to only queries in a non-only query' do t = Task.first - result = @presenter_collection.presenting("tasks", :params => { :include => "restricted" }, :max_per_page => 2) { Task.where(:id => t.id) } + result = @presenter_collection.presenting('tasks', params: { include: 'restricted' }, max_per_page: 2) { Task.where(id: t.id) } expect(result[:tasks][t.id.to_s].keys).not_to include(:restricted_id) expect(result.keys).not_to include(:restricted_associations) end end - describe "polymorphic associations" do - it "works with polymorphic associations" do - result = @presenter_collection.presenting("posts", :params => { :include => "subject" }) { Post.order('id desc') } + describe 'polymorphic associations' do + it 'works with polymorphic associations' do + result = @presenter_collection.presenting('posts', params: { include: 'subject' }) { Post.order('id desc') } expect(result[:posts][Post.first.id.to_s]).to be_present expect(result[:workspaces][Workspace.first.id.to_s]).to be_present expect(result[:tasks][Task.first.id.to_s]).to be_present end - it "does not return an empty hash when none are found" do - result = @presenter_collection.presenting("posts", :params => { :include => "subject" }) { Post.where(:id => nil) } + it 'does not return an empty hash when none are found' do + result = @presenter_collection.presenting('posts', params: { include: 'subject' }) { Post.where(id: nil) } expect(result).to have_key(:posts) expect(result).not_to have_key(:workspaces) expect(result).not_to have_key(:tasks) @@ -310,356 +310,355 @@ class MyException < Exception; end end end - describe "handling of only" do - it "accepts params[:only] as a list of ids to limit to" do - result = @presenter_collection.presenting("workspaces", :params => { :only => Workspace.limit(2).pluck(:id).join(",") }) { Workspace.order("id desc") } + describe 'handling of only' do + it 'accepts params[:only] as a list of ids to limit to' do + result = @presenter_collection.presenting('workspaces', params: { only: Workspace.limit(2).pluck(:id).join(',') }) { Workspace.order('id desc') } expect(result[:workspaces].keys).to match_array(Workspace.limit(2).pluck(:id).map(&:to_s)) end - it "does not paginate only requests" do + it 'does not paginate only requests' do dont_allow(@presenter_collection).paginate - @presenter_collection.presenting("workspaces", :params => { :only => Workspace.limit(2).pluck(:id).join(",") }) { Workspace.order("id desc") } + @presenter_collection.presenting('workspaces', params: { only: Workspace.limit(2).pluck(:id).join(',') }) { Workspace.order('id desc') } end - it "escapes ids" do - result = @presenter_collection.presenting("workspaces", :params => { :only => "#{Workspace.first.id}foo,;drop tables;,#{Workspace.first.id}" }) { Workspace.order("id desc") } + it 'escapes ids' do + result = @presenter_collection.presenting('workspaces', params: { only: "#{Workspace.first.id}foo,;drop tables;,#{Workspace.first.id}" }) { Workspace.order('id desc') } expect(result[:workspaces].length).to eq(1) end - it "only runs when it receives ids" do - result = @presenter_collection.presenting("workspaces", :params => { :only => "" }) { Workspace.order("id desc") } + it 'only runs when it receives ids' do + result = @presenter_collection.presenting('workspaces', params: { only: '' }) { Workspace.order('id desc') } expect(result[:workspaces].length).to be > 1 - result = @presenter_collection.presenting("workspaces", :params => { :only => "1" }) { Workspace.order("id desc") } + result = @presenter_collection.presenting('workspaces', params: { only: '1' }) { Workspace.order('id desc') } expect(result[:workspaces].length).to be <= 1 end end - describe "filters" do + describe 'filters' do before do WorkspacePresenter.filter(:owned_by) { |scope, user_id| scope.owned_by(user_id.to_i) } - WorkspacePresenter.filter(:title) { |scope, title| scope.where(:title => title) } + WorkspacePresenter.filter(:title) { |scope, title| scope.where(title: title) } end - it "limits records to those matching given filters" do - result = @presenter_collection.presenting("workspaces", :params => { :owned_by => bob.id.to_s }) { Workspace.order("id desc") } # hit the API, filtering on owned_by:bob + it 'limits records to those matching given filters' do + result = @presenter_collection.presenting('workspaces', params: { owned_by: bob.id.to_s }) { Workspace.order('id desc') } # hit the API, filtering on owned_by:bob expect(result[:workspaces]).to be_present - expect(result[:workspaces].keys.all? {|id| bob_workspaces_ids.map(&:to_s).include?(id) }).to be_truthy # all of the returned workspaces should contain bob + expect(result[:workspaces].keys.all? { |id| bob_workspaces_ids.map(&:to_s).include?(id) }).to be_truthy # all of the returned workspaces should contain bob end - it "returns all records if filters are not given" do - result = @presenter_collection.presenting("workspaces") { Workspace.order("id desc") } # hit the API again, this time not filtering on anything - expect(result[:workspaces].keys.all? {|id| bob_workspaces_ids.map(&:to_s).include?(id) }).to be_falsey # the returned workspaces no longer all contain bob + it 'returns all records if filters are not given' do + result = @presenter_collection.presenting('workspaces') { Workspace.order('id desc') } # hit the API again, this time not filtering on anything + expect(result[:workspaces].keys.all? { |id| bob_workspaces_ids.map(&:to_s).include?(id) }).to be_falsey # the returned workspaces no longer all contain bob end - it "ignores unknown filters" do - result = @presenter_collection.presenting("workspaces", :params => { :wut => "is this?" }) { Workspace.order("id desc") } - expect(result[:workspaces].keys.all? {|id| bob_workspaces_ids.map(&:to_s).include?(id) }).to be_falsey + it 'ignores unknown filters' do + result = @presenter_collection.presenting('workspaces', params: { wut: 'is this?' }) { Workspace.order('id desc') } + expect(result[:workspaces].keys.all? { |id| bob_workspaces_ids.map(&:to_s).include?(id) }).to be_falsey end - it "limits records to those matching all given filters" do - result = @presenter_collection.presenting("workspaces", :params => { :owned_by => bob.id.to_s, :title => "bob workspace 1" }) { Workspace.order("id desc") } # try two filters - expect(result[:results].first[:id]).to eq(Workspace.where(:title => "bob workspace 1").first.id.to_s) + it 'limits records to those matching all given filters' do + result = @presenter_collection.presenting('workspaces', params: { owned_by: bob.id.to_s, title: 'bob workspace 1' }) { Workspace.order('id desc') } # try two filters + expect(result[:results].first[:id]).to eq(Workspace.where(title: 'bob workspace 1').first.id.to_s) end - it "converts boolean parameters from strings to booleans" do - WorkspacePresenter.filter(:owned_by_bob) { |scope, boolean| boolean ? scope.where(:user_id => bob.id) : scope.where(:user_id => jane.id) } - result = @presenter_collection.presenting("workspaces", :params => { :owned_by_bob => "false" }) { Workspace.where(nil) } - expect(result[:workspaces].values.find { |workspace| workspace[:title].include?("jane") }).to be - expect(result[:workspaces].values.find { |workspace| workspace[:title].include?("bob") }).not_to be + it 'converts boolean parameters from strings to booleans' do + WorkspacePresenter.filter(:owned_by_bob) { |scope, boolean| boolean ? scope.where(user_id: bob.id) : scope.where(user_id: jane.id) } + result = @presenter_collection.presenting('workspaces', params: { owned_by_bob: 'false' }) { Workspace.where(nil) } + expect(result[:workspaces].values.find { |workspace| workspace[:title].include?('jane') }).to be + expect(result[:workspaces].values.find { |workspace| workspace[:title].include?('bob') }).not_to be end - it "ensures arguments are strings if they are not arrays" do + it 'ensures arguments are strings if they are not arrays' do filter_was_run = false WorkspacePresenter.filter(:owned_by_bob) do |scope, string| filter_was_run = true expect(string).to be_a(String) scope end - @presenter_collection.presenting("workspaces", :params => { :owned_by_bob => { :wut => "is this?" } }) { Workspace.where(nil) } + @presenter_collection.presenting('workspaces', params: { owned_by_bob: { wut: 'is this?' } }) { Workspace.where(nil) } expect(filter_was_run).to be_truthy end - it "preserves array arguments" do + it 'preserves array arguments' do filter_was_run = false WorkspacePresenter.filter(:owned_by_bob) do |scope, array| filter_was_run = true expect(array).to be_a(Array) scope end - @presenter_collection.presenting("workspaces", :params => { :owned_by_bob => [1, 2] }) { Workspace.where(nil) } + @presenter_collection.presenting('workspaces', params: { owned_by_bob: [1, 2] }) { Workspace.where(nil) } expect(filter_was_run).to be_truthy end - it "allows filters to be called with false as an argument" do - WorkspacePresenter.filter(:nothing) { |scope, bool| bool ? scope.where(:id => nil) : scope } - result = @presenter_collection.presenting("workspaces", :params => { :nothing => "true" }) { Workspace.where(nil) } + it 'allows filters to be called with false as an argument' do + WorkspacePresenter.filter(:nothing) { |scope, bool| bool ? scope.where(id: nil) : scope } + result = @presenter_collection.presenting('workspaces', params: { nothing: 'true' }) { Workspace.where(nil) } expect(result[:workspaces].length).to eq(0) - result = @presenter_collection.presenting("workspaces", :params => { :nothing => "false" }) { Workspace.where(nil) } + result = @presenter_collection.presenting('workspaces', params: { nothing: 'false' }) { Workspace.where(nil) } expect(result[:workspaces].length).not_to eq(0) end - it "passes colon separated params through as a string" do - WorkspacePresenter.filter(:between) { |scope, a_and_b| + it 'passes colon separated params through as a string' do + WorkspacePresenter.filter(:between) do |scope, a_and_b| a, b = a_and_b.split(':') - expect(a).to eq("1") - expect(b).to eq("10") + expect(a).to eq('1') + expect(b).to eq('10') scope - } + end - @presenter_collection.presenting("workspaces", :params => { :between => "1:10" }) { Workspace.where(nil) } + @presenter_collection.presenting('workspaces', params: { between: '1:10' }) { Workspace.where(nil) } end - context "with defaults" do + context 'with defaults' do before do - WorkspacePresenter.filter(:owner, :default => bob.id) { |scope, id| scope.owned_by(id) } + WorkspacePresenter.filter(:owner, default: bob.id) { |scope, id| scope.owned_by(id) } end - let(:jane) { User.where(:username => "jane").first } + let(:jane) { User.where(username: 'jane').first } - it "applies the filter when it is not requested" do - result = @presenter_collection.presenting("workspaces") { Workspace.order('id desc') } + it 'applies the filter when it is not requested' do + result = @presenter_collection.presenting('workspaces') { Workspace.order('id desc') } expect(result[:workspaces].keys).to match_array(bob.workspaces.map(&:id).map(&:to_s)) end - it "allows falsy defaults" do - WorkspacePresenter.filter(:include_early_workspaces, :default => false) { |scope, bool| bool ? scope : scope.where("id > 3") } - result = @presenter_collection.presenting("workspaces") { Workspace.unscoped } - expect(result[:workspaces]["2"]).not_to be_present - result = @presenter_collection.presenting("workspaces", :params => { :include_early_workspaces => "true" }) { Workspace.unscoped } - expect(result[:workspaces]["2"]).to be_present + it 'allows falsy defaults' do + WorkspacePresenter.filter(:include_early_workspaces, default: false) { |scope, bool| bool ? scope : scope.where('id > 3') } + result = @presenter_collection.presenting('workspaces') { Workspace.unscoped } + expect(result[:workspaces]['2']).not_to be_present + result = @presenter_collection.presenting('workspaces', params: { include_early_workspaces: 'true' }) { Workspace.unscoped } + expect(result[:workspaces]['2']).to be_present end - it "allows defaults to be skipped if :apply_default_filters is false" do - WorkspacePresenter.filter(:include_early_workspaces, :default => false) { |scope, bool| bool ? scope : scope.where("id > 3") } - result = @presenter_collection.presenting("workspaces", :apply_default_filters => true) { Workspace.unscoped } - expect(result[:workspaces]["2"]).not_to be_present - result = @presenter_collection.presenting("workspaces", :apply_default_filters => false) { Workspace.unscoped } - expect(result[:workspaces]["2"]).to be_present + it 'allows defaults to be skipped if :apply_default_filters is false' do + WorkspacePresenter.filter(:include_early_workspaces, default: false) { |scope, bool| bool ? scope : scope.where('id > 3') } + result = @presenter_collection.presenting('workspaces', apply_default_filters: true) { Workspace.unscoped } + expect(result[:workspaces]['2']).not_to be_present + result = @presenter_collection.presenting('workspaces', apply_default_filters: false) { Workspace.unscoped } + expect(result[:workspaces]['2']).to be_present end - it "allows defaults set to false to be skipped if params contain :apply_default_filters with a false value" do - WorkspacePresenter.filter(:include_early_workspaces, :default => false) { |scope, bool| bool ? scope : scope.where("id > 3") } + it 'allows defaults set to false to be skipped if params contain :apply_default_filters with a false value' do + WorkspacePresenter.filter(:include_early_workspaces, default: false) { |scope, bool| bool ? scope : scope.where('id > 3') } - result = @presenter_collection.presenting("workspaces", :params => { :apply_default_filters => "true" }) { Workspace.unscoped } - expect(result[:workspaces]["2"]).not_to be_present + result = @presenter_collection.presenting('workspaces', params: { apply_default_filters: 'true' }) { Workspace.unscoped } + expect(result[:workspaces]['2']).not_to be_present - result = @presenter_collection.presenting("workspaces", :params => { :apply_default_filters => true }) { Workspace.unscoped } - expect(result[:workspaces]["2"]).not_to be_present + result = @presenter_collection.presenting('workspaces', params: { apply_default_filters: true }) { Workspace.unscoped } + expect(result[:workspaces]['2']).not_to be_present end - it "allows defaults set to true to be skipped if params contain :apply_default_filters with a false value" do - WorkspacePresenter.filter(:include_early_workspaces, :default => true) { |scope, bool| bool ? scope : scope.where("id > 3") } + it 'allows defaults set to true to be skipped if params contain :apply_default_filters with a false value' do + WorkspacePresenter.filter(:include_early_workspaces, default: true) { |scope, bool| bool ? scope : scope.where('id > 3') } - result = @presenter_collection.presenting("workspaces", :params => { :apply_default_filters => "false" }) { Workspace.unscoped } - expect(result[:workspaces]["2"]).to be_present + result = @presenter_collection.presenting('workspaces', params: { apply_default_filters: 'false' }) { Workspace.unscoped } + expect(result[:workspaces]['2']).to be_present - result = @presenter_collection.presenting("workspaces", :params => { :apply_default_filters => false }) { Workspace.unscoped } - expect(result[:workspaces]["2"]).to be_present + result = @presenter_collection.presenting('workspaces', params: { apply_default_filters: false }) { Workspace.unscoped } + expect(result[:workspaces]['2']).to be_present end - it "allows the default value to be overridden" do - result = @presenter_collection.presenting("workspaces", :params => { :owner => jane.id.to_s }) { Workspace.order('id desc') } + it 'allows the default value to be overridden' do + result = @presenter_collection.presenting('workspaces', params: { owner: jane.id.to_s }) { Workspace.order('id desc') } expect(result[:workspaces].keys).to match_array(jane.workspaces.map(&:id).map(&:to_s)) - WorkspacePresenter.filter(:include_early_workspaces, :default => true) { |scope, bool| bool ? scope : scope.where("id > 3") } - result = @presenter_collection.presenting("workspaces", :params => { :include_early_workspaces => "false" }) { Workspace.unscoped } - expect(result[:workspaces]["2"]).not_to be_present + WorkspacePresenter.filter(:include_early_workspaces, default: true) { |scope, bool| bool ? scope : scope.where('id > 3') } + result = @presenter_collection.presenting('workspaces', params: { include_early_workspaces: 'false' }) { Workspace.unscoped } + expect(result[:workspaces]['2']).not_to be_present end end - context "without blocks" do - let(:bob) { User.where(:username => "bob").first } - let(:jane) { User.where(:username => "jane").first } + context 'without blocks' do + let(:bob) { User.where(username: 'bob').first } + let(:jane) { User.where(username: 'jane').first } before do - WorkspacePresenter.filter(:owned_by, :default => bob.id) - WorkspacePresenter.presents("Workspace") + WorkspacePresenter.filter(:owned_by, default: bob.id) + WorkspacePresenter.presents('Workspace') end - it "calls the named scope with default arguments" do - result = @presenter_collection.presenting("workspaces") { Workspace.where(nil) } + it 'calls the named scope with default arguments' do + result = @presenter_collection.presenting('workspaces') { Workspace.where(nil) } expect(result[:workspaces].keys).to eq(bob.workspaces.pluck(:id).map(&:to_s)) end - it "calls the named scope with given arguments" do - result = @presenter_collection.presenting("workspaces", :params => { :owned_by => jane.id.to_s }) { Workspace.where(nil) } + it 'calls the named scope with given arguments' do + result = @presenter_collection.presenting('workspaces', params: { owned_by: jane.id.to_s }) { Workspace.where(nil) } expect(result[:workspaces].keys).to eq(jane.workspaces.pluck(:id).map(&:to_s)) end - it "can use filters without lambdas in the presenter or model, but behaves strangely when false is given" do + it 'can use filters without lambdas in the presenter or model, but behaves strangely when false is given' do WorkspacePresenter.filter(:numeric_description) - result = @presenter_collection.presenting("workspaces") { Workspace.where(nil) } - expect(result[:workspaces].keys).to eq(%w[1 2 3 4]) + result = @presenter_collection.presenting('workspaces') { Workspace.where(nil) } + expect(result[:workspaces].keys).to eq(%w(1 2 3 4)) - result = @presenter_collection.presenting("workspaces", :params => { :numeric_description => "true" }) { Workspace.where(nil) } - expect(result[:workspaces].keys).to eq(%w[2 4]) + result = @presenter_collection.presenting('workspaces', params: { numeric_description: 'true' }) { Workspace.where(nil) } + expect(result[:workspaces].keys).to eq(%w(2 4)) # This is probably not the behavior that the developer or user intends. You should always use a one-argument lambda in your # model scope declaration! - result = @presenter_collection.presenting("workspaces", :params => { :numeric_description => "false" }) { Workspace.where(nil) } - expect(result[:workspaces].keys).to eq(%w[2 4]) + result = @presenter_collection.presenting('workspaces', params: { numeric_description: 'false' }) { Workspace.where(nil) } + expect(result[:workspaces].keys).to eq(%w(2 4)) end end end - describe "search" do - context "with search method defined" do + describe 'search' do + context 'with search method defined' do before do - WorkspacePresenter.sort_order(:description, "workspaces.description") - WorkspacePresenter.search do |string| + WorkspacePresenter.sort_order(:description, 'workspaces.description') + WorkspacePresenter.search do |_string| [[5, 3], 2] end end - context "and a search request is made" do - it "calls the search method and maintains the resulting order" do - result = @presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.order("id asc") } - expect(result[:workspaces].keys).to eq(%w[5 3]) + context 'and a search request is made' do + it 'calls the search method and maintains the resulting order' do + result = @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.order('id asc') } + expect(result[:workspaces].keys).to eq(%w(5 3)) expect(result[:count]).to eq(2) end - it "does not apply filters" do + it 'does not apply filters' do mock(@presenter_collection).run_filters(anything, anything).times(0) - result = @presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.order("id asc") } + result = @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.order('id asc') } end - it "does not apply ordering" do + it 'does not apply ordering' do mock(@presenter_collection).handle_ordering(anything, anything).times(0) - result = @presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.order("id asc") } + result = @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.order('id asc') } end it "does not try to handle only's" do mock(@presenter_collection).handle_only(anything, anything).times(0) - result = @presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.order("id asc") } + result = @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.order('id asc') } end - it "does not apply pagination" do + it 'does not apply pagination' do mock(@presenter_collection).paginate(anything, anything).times(0) - result = @presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.order("id asc") } + result = @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.order('id asc') } end - it "keeps the records in the order returned by search" do - result = @presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.unscoped } - + it 'keeps the records in the order returned by search' do + result = @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.unscoped } end - it "throws a SearchUnavailableError if the search block returns false" do - WorkspacePresenter.search do |string| + it 'throws a SearchUnavailableError if the search block returns false' do + WorkspacePresenter.search do |_string| false end - expect { - @presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.unscoped } - }.to raise_error(Brainstem::SearchUnavailableError) + expect do + @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.unscoped } + end.to raise_error(Brainstem::SearchUnavailableError) end - describe "passing options to the search block" do - it "passes the search method, the search string, includes, order, and paging options" do + describe 'passing options to the search block' do + it 'passes the search method, the search string, includes, order, and paging options' do WorkspacePresenter.filter(:owned_by) { |scope| scope } WorkspacePresenter.search do |string, options| - expect(string).to eq("blah") - expect(options[:include]).to eq(["tasks", "lead_user"]) + expect(string).to eq('blah') + expect(options[:include]).to eq(%w(tasks lead_user)) expect(options[:owned_by]).to eq(false) - expect(options[:order][:sort_order]).to eq("description") - expect(options[:order][:direction]).to eq("desc") + expect(options[:order][:sort_order]).to eq('description') + expect(options[:order][:direction]).to eq('desc') expect(options[:page]).to eq(2) expect(options[:per_page]).to eq(5) [[1], 1] # returned ids, count - not testing this in this set of specs end - @presenter_collection.presenting("workspaces", :params => { :search => "blah", :include => "tasks,lead_user", :owned_by => "false", :order => "description:desc", :page => 2, :per_page => 5 }) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah', include: 'tasks,lead_user', owned_by: 'false', order: 'description:desc', page: 2, per_page: 5 }) { Workspace.order('id asc') } end - describe "includes" do - it "throws out requested inlcudes that the presenter does not have associations for" do - WorkspacePresenter.search do |string, options| + describe 'includes' do + it 'throws out requested inlcudes that the presenter does not have associations for' do + WorkspacePresenter.search do |_string, options| expect(options[:include]).to eq([]) [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah", :include => "users"}) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah', include: 'users' }) { Workspace.order('id asc') } end end - describe "filters" do - it "passes through the default filters if no filter is requested" do - WorkspacePresenter.filter(:owned_by, :default => true) { |scope| scope } - WorkspacePresenter.search do |string, options| + describe 'filters' do + it 'passes through the default filters if no filter is requested' do + WorkspacePresenter.filter(:owned_by, default: true) { |scope| scope } + WorkspacePresenter.search do |_string, options| expect(options[:owned_by]).to eq(true) [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.order('id asc') } end - it "throws out requested filters that the presenter does not have" do - WorkspacePresenter.search do |string, options| + it 'throws out requested filters that the presenter does not have' do + WorkspacePresenter.search do |_string, options| expect(options[:highest_rated]).to be_nil [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah", :highest_rated => true}) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah', highest_rated: true }) { Workspace.order('id asc') } end - it "does not pass through existing non-default filters that are not requested" do + it 'does not pass through existing non-default filters that are not requested' do WorkspacePresenter.filter(:owned_by) { |scope| scope } - WorkspacePresenter.search do |string, options| - expect(options.has_key?(:owned_by)).to eq(false) + WorkspacePresenter.search do |_string, options| + expect(options.key?(:owned_by)).to eq(false) [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah"}) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.order('id asc') } end end - describe "orders" do - it "passes through the default sort order if no order is requested" do - WorkspacePresenter.default_sort_order("description:desc") - WorkspacePresenter.search do |string, options| - expect(options[:order][:sort_order]).to eq("description") - expect(options[:order][:direction]).to eq("desc") + describe 'orders' do + it 'passes through the default sort order if no order is requested' do + WorkspacePresenter.default_sort_order('description:desc') + WorkspacePresenter.search do |_string, options| + expect(options[:order][:sort_order]).to eq('description') + expect(options[:order][:direction]).to eq('desc') [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah"}) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.order('id asc') } end it "makes the sort order 'updated_at:desc' if the requested order doesn't match an existing sort order and there is no default" do - WorkspacePresenter.search do |string, options| - expect(options[:order][:sort_order]).to eq("updated_at") - expect(options[:order][:direction]).to eq("desc") + WorkspacePresenter.search do |_string, options| + expect(options[:order][:sort_order]).to eq('updated_at') + expect(options[:order][:direction]).to eq('desc') [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah", :order => "created_at:asc"}) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah', order: 'created_at:asc' }) { Workspace.order('id asc') } end - it "sanitizes sort orders" do - WorkspacePresenter.search do |string, options| - expect(options[:order][:sort_order]).to eq("description") - expect(options[:order][:direction]).to eq("asc") + it 'sanitizes sort orders' do + WorkspacePresenter.search do |_string, options| + expect(options[:order][:sort_order]).to eq('description') + expect(options[:order][:direction]).to eq('asc') [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah", :order => "description:owned"}) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah', order: 'description:owned' }) { Workspace.order('id asc') } end end - describe "pagination" do - it "passes through limit and offset if they are requested" do - WorkspacePresenter.search do |string, options| + describe 'pagination' do + it 'passes through limit and offset if they are requested' do + WorkspacePresenter.search do |_string, options| expect(options[:limit]).to eq(1) expect(options[:offset]).to eq(2) [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah", :limit => 1, :offset => 2}) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah', limit: 1, offset: 2 }) { Workspace.order('id asc') } end - it "passes through only limit and offset if all pagination options are requested" do - WorkspacePresenter.search do |string, options| + it 'passes through only limit and offset if all pagination options are requested' do + WorkspacePresenter.search do |_string, options| expect(options[:limit]).to eq(1) expect(options[:offset]).to eq(2) expect(options[:per_page]).to eq(nil) @@ -667,11 +666,11 @@ class MyException < Exception; end [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah", :limit => 1, :offset => 2, :per_page => 3, :page => 4}) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah', limit: 1, offset: 2, per_page: 3, page: 4 }) { Workspace.order('id asc') } end - it "passes through page and per_page when limit not present" do - WorkspacePresenter.search do |string, options| + it 'passes through page and per_page when limit not present' do + WorkspacePresenter.search do |_string, options| expect(options[:limit]).to eq(nil) expect(options[:offset]).to eq(nil) expect(options[:per_page]).to eq(3) @@ -679,11 +678,11 @@ class MyException < Exception; end [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah", :offset => 2, :per_page => 3, :page => 4}) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah', offset: 2, per_page: 3, page: 4 }) { Workspace.order('id asc') } end - it "passes through page and per_page when offset not present" do - WorkspacePresenter.search do |string, options| + it 'passes through page and per_page when offset not present' do + WorkspacePresenter.search do |_string, options| expect(options[:limit]).to eq(nil) expect(options[:offset]).to eq(nil) expect(options[:per_page]).to eq(3) @@ -691,11 +690,11 @@ class MyException < Exception; end [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah", :limit => 1, :per_page => 3, :page => 4}) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah', limit: 1, per_page: 3, page: 4 }) { Workspace.order('id asc') } end - it "passes through page and per_page by default" do - WorkspacePresenter.search do |string, options| + it 'passes through page and per_page by default' do + WorkspacePresenter.search do |_string, options| expect(options[:limit]).to eq(nil) expect(options[:offset]).to eq(nil) expect(options[:per_page]).to eq(20) @@ -703,152 +702,152 @@ class MyException < Exception; end [[1], 1] end - @presenter_collection.presenting("workspaces", :params => { :search => "blah"}) { Workspace.order("id asc") } + @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.order('id asc') } end end end end - context "and there is no search request" do - it "does not call the search method" do - result = @presenter_collection.presenting("workspaces") { Workspace.order("id asc") } + context 'and there is no search request' do + it 'does not call the search method' do + result = @presenter_collection.presenting('workspaces') { Workspace.order('id asc') } expect(result[:workspaces].keys).to eq(Workspace.pluck(:id).map(&:to_s)) end end end - context "without search method defined" do - context "and a search request is made" do - it "returns as if there was no search" do - result = @presenter_collection.presenting("workspaces", :params => { :search => "blah" }) { Workspace.order("id asc") } + context 'without search method defined' do + context 'and a search request is made' do + it 'returns as if there was no search' do + result = @presenter_collection.presenting('workspaces', params: { search: 'blah' }) { Workspace.order('id asc') } expect(result[:workspaces].keys).to eq(Workspace.pluck(:id).map(&:to_s)) end end end end - describe "sorting and ordering" do - context "when there is no sort provided" do - it "returns an empty array when there are no objects" do - result = @presenter_collection.presenting("workspaces") { Workspace.where(:id => nil) } - expect(result).to eq(:count => 0, :workspaces => {}, :results => []) + describe 'sorting and ordering' do + context 'when there is no sort provided' do + it 'returns an empty array when there are no objects' do + result = @presenter_collection.presenting('workspaces') { Workspace.where(id: nil) } + expect(result).to eq(count: 0, workspaces: {}, results: []) end it "falls back to the object's sort order when nothing is provided" do - result = @presenter_collection.presenting("workspaces") { Workspace.where(:id => [1, 3]) } - expect(result[:workspaces].keys).to eq(%w[1 3]) + result = @presenter_collection.presenting('workspaces') { Workspace.where(id: [1, 3]) } + expect(result[:workspaces].keys).to eq(%w(1 3)) end end - it "allows default ordering descending" do - WorkspacePresenter.sort_order(:description, "workspaces.description") - WorkspacePresenter.default_sort_order("description:desc") - result = @presenter_collection.presenting("workspaces") { Workspace.where("id is not null") } - expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(c b a 3 2 1)) + it 'allows default ordering descending' do + WorkspacePresenter.sort_order(:description, 'workspaces.description') + WorkspacePresenter.default_sort_order('description:desc') + result = @presenter_collection.presenting('workspaces') { Workspace.where('id is not null') } + expect(result[:results].map { |i| result[:workspaces][i[:id]][:description] }).to eq(%w(c b a 3 2 1)) end - it "allows default ordering ascending" do - WorkspacePresenter.sort_order(:description, "workspaces.description") - WorkspacePresenter.default_sort_order("description:asc") - result = @presenter_collection.presenting("workspaces") { Workspace.where("id is not null") } - expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(1 2 3 a b c)) + it 'allows default ordering ascending' do + WorkspacePresenter.sort_order(:description, 'workspaces.description') + WorkspacePresenter.default_sort_order('description:asc') + result = @presenter_collection.presenting('workspaces') { Workspace.where('id is not null') } + expect(result[:results].map { |i| result[:workspaces][i[:id]][:description] }).to eq(%w(1 2 3 a b c)) end - it "applies orders that match the default order" do - WorkspacePresenter.sort_order(:description, "workspaces.description") - WorkspacePresenter.default_sort_order("description:desc") - result = @presenter_collection.presenting("workspaces", :params => { :order => "description:desc"} ) { Workspace.where("id is not null") } - expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(c b a 3 2 1)) + it 'applies orders that match the default order' do + WorkspacePresenter.sort_order(:description, 'workspaces.description') + WorkspacePresenter.default_sort_order('description:desc') + result = @presenter_collection.presenting('workspaces', params: { order: 'description:desc' }) { Workspace.where('id is not null') } + expect(result[:results].map { |i| result[:workspaces][i[:id]][:description] }).to eq(%w(c b a 3 2 1)) end - it "applies orders that conflict with the default order" do - WorkspacePresenter.sort_order(:description, "workspaces.description") - WorkspacePresenter.default_sort_order("description:desc") - result = @presenter_collection.presenting("workspaces", :params => { :order => "description:asc"} ) { Workspace.where("id is not null") } - expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(1 2 3 a b c)) + it 'applies orders that conflict with the default order' do + WorkspacePresenter.sort_order(:description, 'workspaces.description') + WorkspacePresenter.default_sort_order('description:desc') + result = @presenter_collection.presenting('workspaces', params: { order: 'description:asc' }) { Workspace.where('id is not null') } + expect(result[:results].map { |i| result[:workspaces][i[:id]][:description] }).to eq(%w(1 2 3 a b c)) end - it "cleans the params" do + it 'cleans the params' do last_direction = nil - WorkspacePresenter.sort_order(:description, "workspaces.description") do |scope, direction| + WorkspacePresenter.sort_order(:description, 'workspaces.description') do |scope, direction| last_direction = direction scope end - WorkspacePresenter.sort_order(:title, "workspaces.title") - WorkspacePresenter.default_sort_order("description:desc") + WorkspacePresenter.sort_order(:title, 'workspaces.title') + WorkspacePresenter.default_sort_order('description:desc') - result = @presenter_collection.presenting("workspaces", :params => { :order => "description:drop table" }) { Workspace.where("id is not null") } + result = @presenter_collection.presenting('workspaces', params: { order: 'description:drop table' }) { Workspace.where('id is not null') } expect(last_direction).to eq('asc') expect(result.keys).to match_array([:count, :workspaces, :results]) - result = @presenter_collection.presenting("workspaces", :params => { :order => "description:;;hacker;;" }) { Workspace.where("id is not null") } + result = @presenter_collection.presenting('workspaces', params: { order: 'description:;;hacker;;' }) { Workspace.where('id is not null') } expect(last_direction).to eq('asc') - result = @presenter_collection.presenting("workspaces", :params => { :order => "description:desc" }) { Workspace.where("id is not null") } + result = @presenter_collection.presenting('workspaces', params: { order: 'description:desc' }) { Workspace.where('id is not null') } expect(last_direction).to eq('desc') - result = @presenter_collection.presenting("workspaces", :params => { :order => "description:asc" }) { Workspace.where("id is not null") } + result = @presenter_collection.presenting('workspaces', params: { order: 'description:asc' }) { Workspace.where('id is not null') } expect(last_direction).to eq('asc') - result = @presenter_collection.presenting("workspaces", :params => { :order => "drop table:desc" }) { Workspace.where("id is not null") } + result = @presenter_collection.presenting('workspaces', params: { order: 'drop table:desc' }) { Workspace.where('id is not null') } expect(last_direction).to eq('desc') - result = @presenter_collection.presenting("workspaces", :params => { :order => "title:desc" }) { Workspace.where("id is not null") } - expect(result[:results].map {|i| result[:workspaces][i[:id]][:title] }).to eq(["jane workspace 2", "jane workspace 1", "bob workspace 4", "bob workspace 3", "bob workspace 2", "bob workspace 1"]) + result = @presenter_collection.presenting('workspaces', params: { order: 'title:desc' }) { Workspace.where('id is not null') } + expect(result[:results].map { |i| result[:workspaces][i[:id]][:title] }).to eq(['jane workspace 2', 'jane workspace 1', 'bob workspace 4', 'bob workspace 3', 'bob workspace 2', 'bob workspace 1']) - result = @presenter_collection.presenting("workspaces", :params => { :order => "title:hacker" }) { Workspace.where("id is not null") } - expect(result[:results].map {|i| result[:workspaces][i[:id]][:title] }).to eq(["bob workspace 1", "bob workspace 2", "bob workspace 3", "bob workspace 4", "jane workspace 1", "jane workspace 2"]) + result = @presenter_collection.presenting('workspaces', params: { order: 'title:hacker' }) { Workspace.where('id is not null') } + expect(result[:results].map { |i| result[:workspaces][i[:id]][:title] }).to eq(['bob workspace 1', 'bob workspace 2', 'bob workspace 3', 'bob workspace 4', 'jane workspace 1', 'jane workspace 2']) - result = @presenter_collection.presenting("workspaces", :params => { :order => "title:;;;drop table;;" }) { Workspace.where("id is not null") } - expect(result[:results].map {|i| result[:workspaces][i[:id]][:title] }).to eq(["bob workspace 1", "bob workspace 2", "bob workspace 3", "bob workspace 4", "jane workspace 1", "jane workspace 2"]) + result = @presenter_collection.presenting('workspaces', params: { order: 'title:;;;drop table;;' }) { Workspace.where('id is not null') } + expect(result[:results].map { |i| result[:workspaces][i[:id]][:title] }).to eq(['bob workspace 1', 'bob workspace 2', 'bob workspace 3', 'bob workspace 4', 'jane workspace 1', 'jane workspace 2']) end - it "can take a proc" do + it 'can take a proc' do WorkspacePresenter.sort_order(:id) { |scope, direction| scope.order("workspaces.id #{direction}") } - WorkspacePresenter.default_sort_order("id:asc") + WorkspacePresenter.default_sort_order('id:asc') # Default - result = @presenter_collection.presenting("workspaces") { Workspace.where("id is not null") } - expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(a 1 b 2 c 3)) + result = @presenter_collection.presenting('workspaces') { Workspace.where('id is not null') } + expect(result[:results].map { |i| result[:workspaces][i[:id]][:description] }).to eq(%w(a 1 b 2 c 3)) # Asc - result = @presenter_collection.presenting("workspaces", :params => { :order => "id:asc" }) { Workspace.where("id is not null") } - expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(a 1 b 2 c 3)) + result = @presenter_collection.presenting('workspaces', params: { order: 'id:asc' }) { Workspace.where('id is not null') } + expect(result[:results].map { |i| result[:workspaces][i[:id]][:description] }).to eq(%w(a 1 b 2 c 3)) # Desc - result = @presenter_collection.presenting("workspaces", :params => { :order => "id:desc" }) { Workspace.where("id is not null") } - expect(result[:results].map {|i| result[:workspaces][i[:id]][:description] }).to eq(%w(3 c 2 b 1 a)) + result = @presenter_collection.presenting('workspaces', params: { order: 'id:desc' }) { Workspace.where('id is not null') } + expect(result[:results].map { |i| result[:workspaces][i[:id]][:description] }).to eq(%w(3 c 2 b 1 a)) end end - describe "the :as param" do - it "determines the chosen top-level key name" do - result = @presenter_collection.presenting("workspaces", :as => :my_workspaces) { Workspace.where(:id => 1) } + describe 'the :as param' do + it 'determines the chosen top-level key name' do + result = @presenter_collection.presenting('workspaces', as: :my_workspaces) { Workspace.where(id: 1) } expect(result.keys).to eq([:count, :my_workspaces, :results]) end end - describe "the count top level key" do - it "should return the total number of matched records" do + describe 'the count top level key' do + it 'should return the total number of matched records' do WorkspacePresenter.filter(:owned_by) { |scope, user_id| scope.owned_by(user_id.to_i) } - result = @presenter_collection.presenting("workspaces") { Workspace.where(:id => 1) } + result = @presenter_collection.presenting('workspaces') { Workspace.where(id: 1) } expect(result[:count]).to eq(1) - result = @presenter_collection.presenting("workspaces") { Workspace.unscoped } + result = @presenter_collection.presenting('workspaces') { Workspace.unscoped } expect(result[:count]).to eq(Workspace.count) - result = @presenter_collection.presenting("workspaces", :params => { :owned_by => bob.to_param }) { Workspace.unscoped } + result = @presenter_collection.presenting('workspaces', params: { owned_by: bob.to_param }) { Workspace.unscoped } expect(result[:count]).to eq(Workspace.owned_by(bob.to_param).count) - result = @presenter_collection.presenting("workspaces", :params => { :owned_by => bob.to_param }) { Workspace.group(:id) } + result = @presenter_collection.presenting('workspaces', params: { owned_by: bob.to_param }) { Workspace.group(:id) } expect(result[:count]).to eq(Workspace.owned_by(bob.to_param).count) end end end - describe "collection methods" do - describe "for method" do + describe 'collection methods' do + describe 'for method' do module V1 class ArrayPresenter < Brainstem::Presenter end @@ -858,26 +857,26 @@ class ArrayPresenter < Brainstem::Presenter V1::ArrayPresenter.presents Array end - it "returns the presenter for a given class" do - expect(Brainstem.presenter_collection("v1").for(Array)).to be_a(V1::ArrayPresenter) + it 'returns the presenter for a given class' do + expect(Brainstem.presenter_collection('v1').for(Array)).to be_a(V1::ArrayPresenter) end - it "returns nil when given nil" do - expect(Brainstem.presenter_collection("v1").for(nil)).to be_nil + it 'returns nil when given nil' do + expect(Brainstem.presenter_collection('v1').for(nil)).to be_nil end - it "returns nil when a given class has no presenter" do - expect(Brainstem.presenter_collection("v1").for(String)).to be_nil + it 'returns nil when a given class has no presenter' do + expect(Brainstem.presenter_collection('v1').for(String)).to be_nil end - it "uses the default namespace when the passed namespace is nil" do + it 'uses the default namespace when the passed namespace is nil' do expect(Brainstem.presenter_collection).to eq(Brainstem.presenter_collection(nil)) end end - describe "for! method" do - it "raises if there is no presenter for the given class" do - expect{ Brainstem.presenter_collection("v1").for!(String) }.to raise_error(ArgumentError) + describe 'for! method' do + it 'raises if there is no presenter for the given class' do + expect { Brainstem.presenter_collection('v1').for!(String) }.to raise_error(ArgumentError) end end end diff --git a/spec/brainstem/presenter_spec.rb b/spec/brainstem/presenter_spec.rb index d1ac96ee..1e6bf54b 100644 --- a/spec/brainstem/presenter_spec.rb +++ b/spec/brainstem/presenter_spec.rb @@ -1,48 +1,47 @@ require 'spec_helper' describe Brainstem::Presenter do - describe "class methods" do - - describe "presents method" do + describe 'class methods' do + describe 'presents method' do before do @klass = Class.new(Brainstem::Presenter) end - it "records itself as the presenter for the named class as a string" do - @klass.presents "String" + it 'records itself as the presenter for the named class as a string' do + @klass.presents 'String' expect(Brainstem.presenter_collection.for(String)).to be_a(@klass) end - it "records itself as the presenter for the given class" do + it 'records itself as the presenter for the given class' do @klass.presents String expect(Brainstem.presenter_collection.for(String)).to be_a(@klass) end - it "records itself as the presenter for the named classes" do + it 'records itself as the presenter for the named classes' do @klass.presents String, Array expect(Brainstem.presenter_collection.for(String)).to be_a(@klass) expect(Brainstem.presenter_collection.for(Array)).to be_a(@klass) end end - describe "implicit namespacing" do + describe 'implicit namespacing' do module V1 class SomePresenter < Brainstem::Presenter end end - it "uses the closest module name as the presenter namespace" do + it 'uses the closest module name as the presenter namespace' do V1::SomePresenter.presents String expect(Brainstem.presenter_collection(:v1).for(String)).to be_a(V1::SomePresenter) end - it "does not map namespaced presenters into the default namespace" do + it 'does not map namespaced presenters into the default namespace' do V1::SomePresenter.presents String expect(Brainstem.presenter_collection.for(String)).to be_nil end end - describe "helper method" do + describe 'helper method' do before do @klass = Class.new(Brainstem::Presenter) do def call_helper @@ -51,57 +50,57 @@ def call_helper end @helper = Module.new do def foo - "I work" + 'I work' end end end - it "includes and extends the given module" do + it 'includes and extends the given module' do expect { @klass.new.call_helper }.to raise_error @klass.helper @helper - expect(@klass.new.call_helper).to eq("I work") - expect(@klass.foo).to eq("I work") + expect(@klass.new.call_helper).to eq('I work') + expect(@klass.foo).to eq('I work') end end - describe "filter method" do + describe 'filter method' do before do @klass = Class.new(Brainstem::Presenter) end - it "creates an entry in the filters class ivar" do - @klass.filter(:foo, :default => true) { 1 } - expect(@klass.filters[:foo][0]).to eq({"default" => true}) + it 'creates an entry in the filters class ivar' do + @klass.filter(:foo, default: true) { 1 } + expect(@klass.filters[:foo][0]).to eq('default' => true) expect(@klass.filters[:foo][1]).to be_a(Proc) end - it "accepts names without blocks" do + it 'accepts names without blocks' do @klass.filter(:foo) expect(@klass.filters[:foo][1]).to be_nil end end - describe "search method" do + describe 'search method' do before do @klass = Class.new(Brainstem::Presenter) end - it "creates an entry in the search class ivar" do - @klass.search do end + it 'creates an entry in the search class ivar' do + @klass.search {} expect(@klass.search_block).to be_a(Proc) end end end - describe "post_process hooks" do - describe "adding object ids as strings" do + describe 'post_process hooks' do + describe 'adding object ids as strings' do before do post_presenter = Class.new(Brainstem::Presenter) do presents Post def present(model) { - :body => model.body, + body: model.body } end end @@ -117,17 +116,17 @@ def present(model) end end - describe "converting dates and times" do - it "should convert all Time-and-date-like objects to iso8601" do + describe 'converting dates and times' do + it 'should convert all Time-and-date-like objects to iso8601' do class TimePresenter < Brainstem::Presenter - def present(model) + def present(_model) { - :time => Time.now, - :date => Date.new, - :recursion => { - :time => Time.now, - :something => [Time.now, :else], - :foo => :bar + time: Time.now, + date: Date.new, + recursion: { + time: Time.now, + something: [Time.now, :else], + foo: :bar } } end @@ -146,17 +145,17 @@ def present(model) end end - describe "outputting polymorphic associations" do + describe 'outputting polymorphic associations' do before do some_presenter = Class.new(Brainstem::Presenter) do presents Post def present(model) { - :body => model.body, - :subject => association(:subject), - :another_subject => association(:subject), - :something_else => association(:subject, :ignore_type => true) + body: model.body, + subject: association(:subject), + another_subject: association(:subject), + something_else: association(:subject, ignore_type: true) } end end @@ -166,88 +165,87 @@ def present(model) let(:presented_data) { @presenter.present_and_post_process(post) } - context "when polymorphic association exists" do + context 'when polymorphic association exists' do let(:post) { Post.find(1) } - - it "outputs the object as a hash with the id & class table name" do - expect(presented_data[:subject_ref]).to eq({ :id => post.subject.id.to_s, - :key => post.subject.class.table_name }) + it 'outputs the object as a hash with the id & class table name' do + expect(presented_data[:subject_ref]).to eq(id: post.subject.id.to_s, + key: post.subject.class.table_name) end - it "outputs custom names for the object as a hash with the id & class table name" do - expect(presented_data[:another_subject_ref]).to eq({ :id => post.subject.id.to_s, - :key => post.subject.class.table_name }) + it 'outputs custom names for the object as a hash with the id & class table name' do + expect(presented_data[:another_subject_ref]).to eq(id: post.subject.id.to_s, + key: post.subject.class.table_name) end - it "skips the polymorphic handling when ignore_type is true" do + it 'skips the polymorphic handling when ignore_type is true' do expect(presented_data[:something_else_id]).to eq(post.subject.id.to_s) expect(presented_data).not_to have_key(:something_else_type) expect(presented_data).not_to have_key(:something_else_ref) end end - context "when polymorphic association does not exist" do + context 'when polymorphic association does not exist' do let(:post) { Post.find(3) } - it "outputs nil" do + it 'outputs nil' do expect(presented_data[:subject_ref]).to be_nil end - it "outputs nil" do + it 'outputs nil' do expect(presented_data[:another_subject_ref]).to be_nil end end end - describe "outputting associations" do + describe 'outputting associations' do before do some_presenter = Class.new(Brainstem::Presenter) do presents Workspace def present(model) { - :updated_at => model.updated_at, - :tasks => association(:tasks), - :user => association(:user), - :something => association(:user), - :lead_user => association(:lead_user), - :lead_user_with_lambda => association(:json_name => "users") { |model| model.user }, - :tasks_with_lambda => association(:json_name => "tasks") { |model| Task.where(:workspace_id => model) }, - :synthetic => association(:synthetic) + updated_at: model.updated_at, + tasks: association(:tasks), + user: association(:user), + something: association(:user), + lead_user: association(:lead_user), + lead_user_with_lambda: association(json_name: 'users') { |model| model.user }, + tasks_with_lambda: association(json_name: 'tasks') { |model| Task.where(workspace_id: model) }, + synthetic: association(:synthetic) } end end @presenter = some_presenter.new - @workspace = Workspace.find_by_title "bob workspace 1" + @workspace = Workspace.find_by_title 'bob workspace 1' end - it "should not convert or return non-included associations, but should return _id for belongs_to relationships, plus all fields" do + it 'should not convert or return non-included associations, but should return _id for belongs_to relationships, plus all fields' do json = @presenter.present_and_post_process(@workspace, []) expect(json.keys).to match_array([:id, :updated_at, :something_id, :user_id]) end - it "should convert requested has_many associations (includes) into the _ids format" do + it 'should convert requested has_many associations (includes) into the _ids format' do expect(@workspace.tasks.length).to be > 0 - expect(@presenter.present_and_post_process(@workspace, ["tasks"])[:task_ids]).to match_array(@workspace.tasks.map(&:id).map(&:to_s)) + expect(@presenter.present_and_post_process(@workspace, ['tasks'])[:task_ids]).to match_array(@workspace.tasks.map(&:id).map(&:to_s)) end - it "should convert requested belongs_to and has_one associations into the _id format when requested" do - expect(@presenter.present_and_post_process(@workspace, ["user"])[:user_id]).to eq(@workspace.user.id.to_s) + it 'should convert requested belongs_to and has_one associations into the _id format when requested' do + expect(@presenter.present_and_post_process(@workspace, ['user'])[:user_id]).to eq(@workspace.user.id.to_s) end - it "converts non-association models into _id format when they are requested" do - expect(@presenter.present_and_post_process(@workspace, ["lead_user"])[:lead_user_id]).to eq(@workspace.lead_user.id.to_s) + it 'converts non-association models into _id format when they are requested' do + expect(@presenter.present_and_post_process(@workspace, ['lead_user'])[:lead_user_id]).to eq(@workspace.lead_user.id.to_s) end - it "handles associations provided with lambdas" do - expect(@presenter.present_and_post_process(@workspace, ["lead_user_with_lambda"])[:lead_user_with_lambda_id]).to eq(@workspace.lead_user.id.to_s) - expect(@presenter.present_and_post_process(@workspace, ["tasks_with_lambda"])[:tasks_with_lambda_ids]).to eq(@workspace.tasks.map(&:id).map(&:to_s)) + it 'handles associations provided with lambdas' do + expect(@presenter.present_and_post_process(@workspace, ['lead_user_with_lambda'])[:lead_user_with_lambda_id]).to eq(@workspace.lead_user.id.to_s) + expect(@presenter.present_and_post_process(@workspace, ['tasks_with_lambda'])[:tasks_with_lambda_ids]).to eq(@workspace.tasks.map(&:id).map(&:to_s)) end - it "should return _id fields when the given association ids exist on the model whether it is requested or not" do - expect(@presenter.present_and_post_process(@workspace, ["user"])[:user_id]).to eq(@workspace.user_id.to_s) + it 'should return _id fields when the given association ids exist on the model whether it is requested or not' do + expect(@presenter.present_and_post_process(@workspace, ['user'])[:user_id]).to eq(@workspace.user_id.to_s) json = @presenter.present_and_post_process(@workspace, []) expect(json.keys).to match_array([:user_id, :something_id, :id, :updated_at]) @@ -255,19 +253,19 @@ def present(model) expect(json[:something_id]).to eq(@workspace.user_id.to_s) end - it "should return null, not empty string when ids are missing" do + it 'should return null, not empty string when ids are missing' do @workspace.user = nil @workspace.tasks = [] - expect(@presenter.present_and_post_process(@workspace, ["lead_user_with_lambda"])[:lead_user_with_lambda_id]).to eq(nil) - expect(@presenter.present_and_post_process(@workspace, ["user"])[:user_id]).to eq(nil) - expect(@presenter.present_and_post_process(@workspace, ["something"])[:something_id]).to eq(nil) - expect(@presenter.present_and_post_process(@workspace, ["tasks"])[:task_ids]).to eq([]) + expect(@presenter.present_and_post_process(@workspace, ['lead_user_with_lambda'])[:lead_user_with_lambda_id]).to eq(nil) + expect(@presenter.present_and_post_process(@workspace, ['user'])[:user_id]).to eq(nil) + expect(@presenter.present_and_post_process(@workspace, ['something'])[:something_id]).to eq(nil) + expect(@presenter.present_and_post_process(@workspace, ['tasks'])[:task_ids]).to eq([]) end - context "when the model has an _id method but no column" do - it "does not include the _id field" do + context 'when the model has an _id method but no column' do + it 'does not include the _id field' do def @workspace.synthetic_id - raise "this explodes because it's not an association" + fail "this explodes because it's not an association" end expect(@presenter.present_and_post_process(@workspace, [])).not_to have_key(:synthetic_id) end diff --git a/spec/brainstem_spec.rb b/spec/brainstem_spec.rb index 3324aca1..163d3d70 100644 --- a/spec/brainstem_spec.rb +++ b/spec/brainstem_spec.rb @@ -1,25 +1,25 @@ require 'spec_helper' describe Brainstem do - describe "default_namespace attribute" do - it "can be set and read" do - Brainstem.default_namespace = "something" - expect(Brainstem.default_namespace).to eq("something") + describe 'default_namespace attribute' do + it 'can be set and read' do + Brainstem.default_namespace = 'something' + expect(Brainstem.default_namespace).to eq('something') end it "returns 'none' if unset" do - expect(Brainstem.default_namespace).to eq("none") + expect(Brainstem.default_namespace).to eq('none') end end - describe "presenter collection method" do - it "returns an instance of PresenterCollection" do + describe 'presenter collection method' do + it 'returns an instance of PresenterCollection' do expect(Brainstem.presenter_collection).to be_a(Brainstem::PresenterCollection) end - it "accepts a namespace" do - expect(Brainstem.presenter_collection("v1")).to be_a(Brainstem::PresenterCollection) - expect(Brainstem.presenter_collection("v1")).not_to eq(Brainstem.presenter_collection) + it 'accepts a namespace' do + expect(Brainstem.presenter_collection('v1')).to be_a(Brainstem::PresenterCollection) + expect(Brainstem.presenter_collection('v1')).not_to eq(Brainstem.presenter_collection) end end end diff --git a/spec/spec_helpers/cleanup.rb b/spec/spec_helpers/cleanup.rb index 1f2bf7fd..e4b26bf7 100644 --- a/spec/spec_helpers/cleanup.rb +++ b/spec/spec_helpers/cleanup.rb @@ -1,7 +1,6 @@ module Brainstem - def self.clear_collections! - presenter_collection.presenters.each do |klass, presenter| + presenter_collection.presenters.each do |_klass, presenter| presenter.clear_options! end @presenter_collection = {} @@ -19,5 +18,4 @@ def clear_options! self.class.clear_options! end end - -end \ No newline at end of file +end diff --git a/spec/spec_helpers/db.rb b/spec/spec_helpers/db.rb index 38d9b129..8bbe7372 100644 --- a/spec/spec_helpers/db.rb +++ b/spec/spec_helpers/db.rb @@ -1,27 +1,27 @@ -ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:') +ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') ActiveRecord::Schema.define do self.verbose = false - create_table :users, :force => true do |t| + create_table :users, force: true do |t| t.string :username t.timestamps null: true end - create_table :workspaces, :force => true do |t| + create_table :workspaces, force: true do |t| t.string :title t.string :description t.belongs_to :user t.timestamps null: true end - create_table :tasks, :force => true do |t| + create_table :tasks, force: true do |t| t.string :name t.integer :parent_id t.belongs_to :workspace t.timestamps null: true end - create_table :posts, :force => true do |t| + create_table :posts, force: true do |t| t.string :body t.integer :subject_id t.string :subject_type @@ -35,11 +35,11 @@ class User < ActiveRecord::Base class Task < ActiveRecord::Base belongs_to :workspace - has_many :sub_tasks, :foreign_key => :parent_id, :class_name => "Task" + has_many :sub_tasks, foreign_key: :parent_id, class_name: 'Task' has_many :posts def tags - %w[some tags] + %w(some tags) end end @@ -48,8 +48,8 @@ class Workspace < ActiveRecord::Base has_many :tasks has_many :posts - scope :owned_by, -> id { where(:user_id => id) } - scope :numeric_description, -> description { where(:description => ["1", "2", "3"]) } + scope :owned_by, -> id { where(user_id: id) } + scope :numeric_description, -> _description { where(description: %w(1 2 3)) } def lead_user user @@ -57,24 +57,24 @@ def lead_user end class Post < ActiveRecord::Base - belongs_to :subject, :polymorphic => true + belongs_to :subject, polymorphic: true end -User.create!(:id => 1, :username => "bob") -User.create!(:id => 2, :username => "jane") +User.create!(id: 1, username: 'bob') +User.create!(id: 2, username: 'jane') -Workspace.create!(:id => 1, :user_id => 1, :title => "bob workspace 1", :description => "a") -Workspace.create!(:id => 2, :user_id => 1, :title => "bob workspace 2", :description => "1") -Workspace.create!(:id => 3, :user_id => 1, :title => "bob workspace 3", :description => "b") -Workspace.create!(:id => 4, :user_id => 1, :title => "bob workspace 4", :description => "2") -Workspace.create!(:id => 5, :user_id => 2, :title => "jane workspace 1", :description => "c") -Workspace.create!(:id => 6, :user_id => 2, :title => "jane workspace 2", :description => "3") +Workspace.create!(id: 1, user_id: 1, title: 'bob workspace 1', description: 'a') +Workspace.create!(id: 2, user_id: 1, title: 'bob workspace 2', description: '1') +Workspace.create!(id: 3, user_id: 1, title: 'bob workspace 3', description: 'b') +Workspace.create!(id: 4, user_id: 1, title: 'bob workspace 4', description: '2') +Workspace.create!(id: 5, user_id: 2, title: 'jane workspace 1', description: 'c') +Workspace.create!(id: 6, user_id: 2, title: 'jane workspace 2', description: '3') -Task.create!(:id => 1, :workspace_id => 1, :name => "Buy milk") -Task.create!(:id => 2, :workspace_id => 1, :name => "Buy bananas") -Task.create!(:id => 3, :workspace_id => 1, :parent_id => 2, :name => "Green preferred") -Task.create!(:id => 4, :workspace_id => 1, :parent_id => 2, :name => "One bunch") +Task.create!(id: 1, workspace_id: 1, name: 'Buy milk') +Task.create!(id: 2, workspace_id: 1, name: 'Buy bananas') +Task.create!(id: 3, workspace_id: 1, parent_id: 2, name: 'Green preferred') +Task.create!(id: 4, workspace_id: 1, parent_id: 2, name: 'One bunch') -Post.create!(:id => 1, :subject => Workspace.first, :body => "first post!") -Post.create!(:id => 2, :subject => Task.first, :body => "this is important. get on it!") -Post.create!(:id => 3, :body => "Post without subject") \ No newline at end of file +Post.create!(id: 1, subject: Workspace.first, body: 'first post!') +Post.create!(id: 2, subject: Task.first, body: 'this is important. get on it!') +Post.create!(id: 3, body: 'Post without subject') diff --git a/spec/spec_helpers/presenters.rb b/spec/spec_helpers/presenters.rb index 87f191ce..4f39b1fb 100644 --- a/spec/spec_helpers/presenters.rb +++ b/spec/spec_helpers/presenters.rb @@ -1,11 +1,11 @@ class WorkspacePresenter < Brainstem::Presenter def present(model) { - :title => model.title, - :description => model.description, - :updated_at => model.updated_at, - :tasks => association(:tasks), - :lead_user => association(:lead_user, :json_name => "users") + title: model.title, + description: model.description, + updated_at: model.updated_at, + tasks: association(:tasks), + lead_user: association(:lead_user, json_name: 'users') } end end @@ -13,11 +13,11 @@ def present(model) class TaskPresenter < Brainstem::Presenter def present(model) { - :name => model.name, - :sub_tasks => association(:sub_tasks), - :other_tasks => association(:sub_tasks, :json_name => "other_tasks"), - :workspace => association(:workspace), - :restricted => association(:json_name => "restricted_association", :restrict_to_only => true) { |model| model } + name: model.name, + sub_tasks: association(:sub_tasks), + other_tasks: association(:sub_tasks, json_name: 'other_tasks'), + workspace: association(:workspace), + restricted: association(json_name: 'restricted_association', restrict_to_only: true) { |model| model } } end end @@ -25,19 +25,19 @@ def present(model) class UserPresenter < Brainstem::Presenter def present(model) { - :username => model.username, - :odd_workspaces => association(:json_name => "odd_workspaces") { |user| + username: model.username, + odd_workspaces: association(json_name: 'odd_workspaces') do |user| user.workspaces.select { |workspace| workspace.id % 2 == 1 } - } + end } end end - + class PostPresenter < Brainstem::Presenter def present(model) { - :body => model.body, - :subject => association(:subject) + body: model.body, + subject: association(:subject) } end end