forked from yeastymobs/remarkable_mongomapper
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Copy more useful things from Remarkable ActiveRecord.
- Loading branch information
Showing
7 changed files
with
334 additions
and
17 deletions.
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
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,199 @@ | ||
module Remarkable | ||
module ActiveRecord | ||
|
||
def self.after_include(target) #:nodoc: | ||
target.class_inheritable_reader :describe_subject_attributes, :default_subject_attributes | ||
target.send :include, Describe | ||
end | ||
|
||
# Overwrites describe to provide quick way to configure your subject: | ||
# | ||
# describe Post | ||
# should_validate_presente_of :title | ||
# | ||
# describe :published => true do | ||
# should_validate_presence_of :published_at | ||
# end | ||
# end | ||
# | ||
# This is the same as: | ||
# | ||
# describe Post | ||
# should_validate_presente_of :title | ||
# | ||
# describe "when published is true" do | ||
# subject { Post.new(:published => true) } | ||
# should_validate_presence_of :published_at | ||
# end | ||
# end | ||
# | ||
# The string can be localized using I18n. An example yml file is: | ||
# | ||
# locale: | ||
# remarkable: | ||
# mongo_mapper: | ||
# describe: | ||
# each: "{{key}} is {{value}}" | ||
# prepend: "when " | ||
# connector: " and " | ||
# | ||
# You can also call subject attributes to set the default attributes for a | ||
# subject. You can even mix with a fixture replacement tool: | ||
# | ||
# describe Post | ||
# # Fixjour example | ||
# subject_attributes { valid_post_attributes } | ||
# | ||
# describe :published => true do | ||
# should_validate_presence_of :published_at | ||
# end | ||
# end | ||
# | ||
# You can retrieve the merged result of all attributes given using the | ||
# subject_attributes instance method: | ||
# | ||
# describe Post | ||
# # Fixjour example | ||
# subject_attributes { valid_post_attributes } | ||
# | ||
# describe :published => true do | ||
# it "should have default subject attributes" do | ||
# subject_attributes.should == { :title => 'My title', :published => true } | ||
# end | ||
# end | ||
# end | ||
# | ||
module Describe | ||
|
||
def self.included(base) #:nodoc: | ||
base.extend ClassMethods | ||
end | ||
|
||
module ClassMethods | ||
|
||
# Overwrites describe to provide quick way to configure your subject: | ||
# | ||
# describe Post | ||
# should_validate_presente_of :title | ||
# | ||
# describe :published => true do | ||
# should_validate_presence_of :published_at | ||
# end | ||
# end | ||
# | ||
# This is the same as: | ||
# | ||
# describe Post | ||
# should_validate_presente_of :title | ||
# | ||
# describe "when published is true" do | ||
# subject { Post.new(:published => true) } | ||
# should_validate_presence_of :published_at | ||
# end | ||
# end | ||
# | ||
# The string can be localized using I18n. An example yml file is: | ||
# | ||
# locale: | ||
# remarkable: | ||
# mongo_mapper: | ||
# describe: | ||
# each: "{{key}} is {{value}}" | ||
# prepend: "when " | ||
# connector: " and " | ||
# | ||
# See also subject_attributes instance and class methods for more | ||
# information. | ||
# | ||
def describe(*args, &block) | ||
if described_class && args.first.is_a?(Hash) | ||
attributes = args.shift | ||
|
||
connector = Remarkable.t "remarkable.mongo_mapper.describe.connector", :default => " and " | ||
|
||
description = if self.describe_subject_attributes.blank? | ||
Remarkable.t("remarkable.mongo_mapper.describe.prepend", :default => "when ") | ||
else | ||
connector.lstrip | ||
end | ||
|
||
pieces = [] | ||
attributes.each do |key, value| | ||
translated_key = if described_class.respond_to?(:human_attribute_name) | ||
described_class.human_attribute_name(key.to_s, :locale => Remarkable.locale) | ||
else | ||
key.to_s.humanize | ||
end | ||
|
||
pieces << Remarkable.t("remarkable.mongo_mapper.describe.each", | ||
:default => "{{key}} is {{value}}", | ||
:key => translated_key.downcase, :value => value.inspect) | ||
end | ||
|
||
description << pieces.join(connector) | ||
args.unshift(description) | ||
|
||
# Creates an example group, set the subject and eval the given block. | ||
# | ||
example_group = super(*args) do | ||
write_inheritable_hash(:describe_subject_attributes, attributes) | ||
set_described_subject! | ||
instance_eval(&block) | ||
end | ||
else | ||
super(*args, &block) | ||
end | ||
end | ||
|
||
# Sets default attributes for the subject. You can use this to set up | ||
# your subject with valid attributes. You can even mix with a fixture | ||
# replacement tool and still use quick subjects: | ||
# | ||
# describe Post | ||
# # Fixjour example | ||
# subject_attributes { valid_post_attributes } | ||
# | ||
# describe :published => true do | ||
# should_validate_presence_of :published_at | ||
# end | ||
# end | ||
# | ||
def subject_attributes(options=nil, &block) | ||
write_inheritable_attribute(:default_subject_attributes, options || block) | ||
set_described_subject! | ||
end | ||
|
||
def set_described_subject! | ||
subject { | ||
record = self.class.described_class.new | ||
record.send(:attributes=, subject_attributes, false) | ||
record | ||
} | ||
end | ||
end | ||
|
||
# Returns a hash with the subject attributes declared using the | ||
# subject_attributes class method and the attributes given using the | ||
# describe method. | ||
# | ||
# describe Post | ||
# subject_attributes { valid_post_attributes } | ||
# | ||
# describe :published => true do | ||
# it "should have default subject attributes" do | ||
# subject_attributes.should == { :title => 'My title', :published => true } | ||
# end | ||
# end | ||
# end | ||
# | ||
def subject_attributes | ||
default = self.class.default_subject_attributes | ||
default = self.instance_eval(&default) if default.is_a?(Proc) | ||
default ||= {} | ||
|
||
default.merge(self.class.describe_subject_attributes || {}) | ||
end | ||
|
||
end | ||
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,37 @@ | ||
if defined?(Spec) | ||
module Spec #:nodoc: | ||
module Example #:nodoc: | ||
module ExampleGroupMethods #:nodoc: | ||
|
||
# This allows "describe User" to use the I18n human name of User. | ||
# | ||
def self.build_description_with_i18n(*args) | ||
args.inject("") do |description, arg| | ||
arg = if arg.respond_to?(:human_name) | ||
arg.human_name(:locale => Remarkable.locale) | ||
else | ||
arg.to_s | ||
end | ||
|
||
description << " " unless (description == "" || arg =~ /^(\s|\.|#)/) | ||
description << arg | ||
end | ||
end | ||
|
||
# This is for rspec <= 1.1.12. | ||
# | ||
def self.description_text(*args) | ||
self.build_description_with_i18n(*args) | ||
end | ||
|
||
# This is for rspec >= 1.2.0. | ||
# | ||
def self.build_description_from(*args) | ||
text = ExampleGroupMethods.build_description_with_i18n(*args) | ||
text == "" ? nil : text | ||
end | ||
|
||
end | ||
end | ||
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
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,64 @@ | ||
# This is based on Shoulda model builder for Test::Unit. | ||
# | ||
module ModelBuilder | ||
def self.included(base) | ||
return unless base.name =~ /^Spec/ | ||
|
||
base.class_eval do | ||
after(:each) do | ||
if @defined_constants | ||
@defined_constants.each do |class_name| | ||
Object.send(:remove_const, class_name) | ||
end | ||
end | ||
end | ||
end | ||
|
||
base.extend ClassMethods | ||
end | ||
|
||
def define_constant(class_name, &block) | ||
class_name = class_name.to_s.camelize | ||
|
||
klass = Class.new | ||
Object.const_set(class_name, klass) | ||
|
||
klass.class_eval(&block) if block_given? | ||
|
||
@defined_constants ||= [] | ||
@defined_constants << class_name | ||
|
||
klass | ||
end | ||
|
||
def define_model(name, columns = {}, &block) | ||
instance = define_constant(name.to_s.classify, &block).new | ||
|
||
self.class.subject { instance } if self.class.respond_to?(:subject) | ||
instance | ||
end | ||
|
||
module ClassMethods | ||
# This is a macro to run validations of boolean optionals such as :allow_nil | ||
# and :allow_blank. This macro tests all scenarios. The specs must have a | ||
# define_and_validate method defined. | ||
# | ||
def create_optional_boolean_specs(optional, base, options={}) | ||
base.describe "with #{optional} option" do | ||
it { should define_and_validate(options.merge(optional => true)).send(optional) } | ||
it { should define_and_validate(options.merge(optional => false)).send(optional, false) } | ||
it { should_not define_and_validate(options.merge(optional => true)).send(optional, false) } | ||
it { should_not define_and_validate(options.merge(optional => false)).send(optional) } | ||
end | ||
end | ||
|
||
def create_message_specs(base) | ||
base.describe "with message option" do | ||
it { should define_and_validate(:message => 'valid_message').message('valid_message') } | ||
it { should_not define_and_validate(:message => 'not_valid').message('valid_message') } | ||
end | ||
end | ||
end | ||
|
||
end | ||
|
Oops, something went wrong.