Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
inherit_from: .rubocop_todo.yml

Style/StringLiterals:
EnforcedStyle: 'double_quotes'
118 changes: 118 additions & 0 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
source 'https://rubygems.org'
source "https://rubygems.org"

# Specify your gem's dependencies in brainstem.gemspec
gemspec
4 changes: 2 additions & 2 deletions Guardfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme

guard 'rspec' do
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
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ require "bundler/gem_tasks"

require "rspec/core/rake_task"
RSpec::Core::RakeTask.new(:spec)
task :default => :spec
task default: :spec
9 changes: 5 additions & 4 deletions brainstem.gemspec
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
# -*- encoding: utf-8 -*-
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
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.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.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.version = Brainstem::VERSION
Expand All @@ -23,6 +23,7 @@ Gem::Specification.new do |gem|
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
8 changes: 4 additions & 4 deletions lib/brainstem.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ 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.
Expand Down Expand Up @@ -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
6 changes: 3 additions & 3 deletions lib/brainstem/association_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
10 changes: 4 additions & 6 deletions lib/brainstem/controller_methods.rb
Original file line number Diff line number Diff line change
@@ -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.
#
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
40 changes: 19 additions & 21 deletions lib/brainstem/presenter.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
require 'date'
require 'brainstem/association_field'
require 'brainstem/time_classes'
require "date"
require "brainstem/association_field"
require "brainstem/time_classes"

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.
Expand Down Expand Up @@ -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 = {})
Expand All @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -135,10 +133,10 @@ 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')
struct.strftime("%F")
when *TIME_CLASSES # Time, ActiveSupport::TimeWithZone
struct.iso8601
else
Expand All @@ -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
Expand All @@ -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)
Expand Down
Loading