Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
extract(ish) exhibits from OOR code, get tests running
- Loading branch information
Showing
38 changed files
with
1,545 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
source 'http://rubygems.org' | ||
group :development, :test do | ||
gem 'minitest', '~> 2.12.0' | ||
gem 'rr' | ||
gem 'activerecord-nulldb-adapter', :git => "git://github.com/nulldb/nulldb.git" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
GIT | ||
remote: git://github.com/nulldb/nulldb.git | ||
revision: d17674e68c80cb8bb0351ff666797b9f34f9a877 | ||
specs: | ||
activerecord-nulldb-adapter (0.2.1) | ||
activerecord (>= 2.0.0) | ||
|
||
GEM | ||
remote: http://rubygems.org/ | ||
specs: | ||
activemodel (3.2.3) | ||
activesupport (= 3.2.3) | ||
builder (~> 3.0.0) | ||
activerecord (3.2.3) | ||
activemodel (= 3.2.3) | ||
activesupport (= 3.2.3) | ||
arel (~> 3.0.2) | ||
tzinfo (~> 0.3.29) | ||
activesupport (3.2.3) | ||
i18n (~> 0.6) | ||
multi_json (~> 1.0) | ||
arel (3.0.2) | ||
builder (3.0.0) | ||
i18n (0.6.0) | ||
minitest (2.12.1) | ||
multi_json (1.3.4) | ||
rr (1.0.4) | ||
tzinfo (0.3.33) | ||
|
||
PLATFORMS | ||
ruby | ||
|
||
DEPENDENCIES | ||
activerecord-nulldb-adapter! | ||
minitest (~> 2.12.0) | ||
rr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,27 @@ | ||
require 'rake/testtask' | ||
require_relative 'tasks/gemspec' | ||
|
||
namespace 'test' do | ||
test_files = FileList['spec/**/*_spec.rb'] | ||
integration_test_files = FileList['spec/**/*_integration_spec.rb'] | ||
unit_test_files = test_files - integration_test_files | ||
|
||
desc "Run unit tests" | ||
Rake::TestTask.new('unit') do |t| | ||
t.libs.push "lib" | ||
t.test_files = unit_test_files | ||
t.verbose = true | ||
end | ||
|
||
desc "Run integration tests" | ||
Rake::TestTask.new('integration') do |t| | ||
t.libs.push "lib" | ||
t.test_files = integration_test_files | ||
t.verbose = true | ||
end | ||
end | ||
|
||
#Rake::Task['test'].clear | ||
desc "Run all tests" | ||
task 'test' => %w[test:unit test:integration] | ||
task 'default' => 'test' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
require_relative 'exhibit' | ||
|
||
class EnumerableExhibit < Exhibit | ||
include Enumerable | ||
|
||
def self.applicable_to?(object) | ||
# ActiveRecord::Relation, surprisingly, is not Enumerable. But it | ||
# behaves sufficiently similarly for our purposes. | ||
object_is_any_of?(object, 'Enumerable', 'ActiveRecord::Relation') | ||
end | ||
|
||
# Wrap an Enumerable method which returns another collection | ||
def self.exhibit_enum(*method_names, &post_process) | ||
post_process ||= ->(result){exhibit(result)} | ||
method_names.each do |method_name| | ||
define_method(method_name) do |*args, &block| | ||
result = __getobj__.public_send(method_name, *args, &block) | ||
instance_exec(result, &post_process) | ||
end | ||
end | ||
end | ||
private_class_method :exhibit_enum | ||
|
||
exhibit_query :[], :fetch, :slice, :values_at, :last | ||
exhibit_enum :select, :grep, :reject, :to_enum, :sort, :sort_by, :reverse | ||
exhibit_enum :partition do |result| | ||
result.map{|group| exhibit(group)} | ||
end | ||
exhibit_enum :group_by do |result| | ||
result.inject({}) { |h,(k,v)| | ||
h.merge!(k => exhibit(v)) | ||
} | ||
end | ||
|
||
def each(*) | ||
super do |e| | ||
yield exhibit(e) | ||
end | ||
end | ||
|
||
# `render '...', :collection => self` will call #to_ary on this | ||
# before rendering, so we need to be prepared. | ||
def to_ary | ||
self | ||
end | ||
|
||
def render(template) | ||
inject(ActiveSupport::SafeBuffer.new) { |output,element| | ||
output << element.render(template) | ||
} | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
require 'delegate' | ||
require 'active_support/core_ext' | ||
|
||
class Exhibit < SimpleDelegator | ||
def self.exhibits | ||
[ | ||
EnumerableExhibit, | ||
BlogExhibit, | ||
TextPostExhibit, | ||
PicturePostExhibit, | ||
LinkExhibit, | ||
TagListExhibit | ||
] | ||
end | ||
|
||
def self.exhibit(object, context) | ||
return object if exhibited_object?(object) | ||
Rails.logger.debug "Exhibiting #{object.inspect}" | ||
Rails.logger.debug "Exhibit context: #{context}" | ||
object = Exhibited.new(object, context) | ||
exhibits.inject(object) do |object, exhibit_class| | ||
exhibit_class.exhibit_if_applicable(object, context) | ||
end.tap do |obj| | ||
Rails.logger.debug "Exhibits applied: #{obj.inspect_exhibits}" | ||
end | ||
end | ||
|
||
def self.exhibit_if_applicable(object, context) | ||
if applicable_to?(object) | ||
new(object, context) | ||
else | ||
object | ||
end | ||
end | ||
|
||
def self.applicable_to?(object) | ||
false | ||
end | ||
|
||
def self.exhibited_object?(object) | ||
object.respond_to?(:exhibited?) && object.exhibited? | ||
end | ||
|
||
def self.exhibit_query(*method_names) | ||
method_names.each do |name| | ||
define_method(name) do |*args, &block| | ||
exhibit(super(*args, &block)) | ||
end | ||
end | ||
end | ||
private_class_method :exhibit_query | ||
|
||
# A helper for matching models to classes/modules, intended for use | ||
# in .applicable_to?. | ||
def self.object_is_any_of?(object, *classes) | ||
# What with Rails development mode reloading making class matching | ||
# unreliable, plus wanting to avoid adding dependencies to | ||
# external class definitions if we can avoid it, we just match | ||
# against class/module name strings rather than the actual class | ||
# objects. | ||
|
||
# Note that '&' is the set intersection operator for Arrays. | ||
(classes.map(&:to_s) & object.class.ancestors.map(&:name)).any? | ||
end | ||
private_class_method :object_is_any_of? | ||
|
||
attr_reader :context | ||
|
||
def initialize(model, context) | ||
@context = context | ||
super(model) | ||
end | ||
|
||
alias_method :__class__, :class | ||
def class | ||
__getobj__.class | ||
end | ||
|
||
def exhibit(model) | ||
Exhibit.exhibit(model, context) | ||
end | ||
|
||
def to_partial_path | ||
if __getobj__.respond_to?(:to_partial_path) | ||
__getobj__.to_partial_path | ||
else | ||
partialize_name(__getobj__.class.name) | ||
end | ||
end | ||
|
||
def render(template) | ||
template.render(:partial => to_partial_path, :object => self) | ||
end | ||
|
||
def exhibit_chain | ||
inner_exhibits = defined?(super) ? super : [] | ||
[__class__] + inner_exhibits | ||
end | ||
|
||
def inspect_exhibits | ||
exhibit_chain.map(&:to_s).join(':') | ||
end | ||
|
||
def inspect | ||
"#{inspect_exhibits}(#{__getobj__.inspect})" | ||
end | ||
|
||
def exhibited? | ||
true | ||
end | ||
|
||
private | ||
|
||
# The terminator for the exhibit chain, and a marker that an object | ||
# has been through the exhibit process | ||
class Exhibited < Exhibit | ||
def exhibit_chain | ||
[] | ||
end | ||
|
||
def to_model | ||
__getobj__ | ||
end | ||
end | ||
|
||
def partialize_name(name) | ||
"/#{name.underscore.pluralize}/#{name.demodulize.underscore}" | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module ExhibitsHelper | ||
def exhibit(model, context=self) | ||
Exhibit.exhibit(model, context) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
require_relative '../spec_helper_lite' | ||
require_relative '../fixtures/exhibits/blog_exhibit' | ||
|
||
describe BlogExhibit do | ||
subject { BlogExhibit.new(blog, context) } | ||
let(:blog) { OpenStruct.new(:tags => tags) } | ||
let(:tags) { Object.new } | ||
let(:context) { Object.new } | ||
|
||
it 'exhibits its tags' do | ||
exhibited_tags = Object.new | ||
mock(subject).exhibit(tags) { exhibited_tags } | ||
subject.tags.must_be_same_as(exhibited_tags) | ||
end | ||
|
||
describe '#filter_by_tag' do | ||
it 'exhibits the result' do | ||
exhibited_blog = Object.new | ||
filtered_blog = Object.new | ||
mock(blog).filter_by_tag("foo") { filtered_blog } | ||
mock(subject).exhibit(filtered_blog) { exhibited_blog } | ||
subject.filter_by_tag("foo").must_be_same_as(exhibited_blog) | ||
|
||
end | ||
end | ||
end |
Oops, something went wrong.