Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added the `Tire::Model::DynamicPersistence` extension

Related: karmi/retire#605

Closes #14
  • Loading branch information...
commit 8fe8f5ef13e81c87aa67c1ddba82e092046517d2 1 parent eace50c
@davekinkead davekinkead authored committed
View
4 README.markdown
@@ -15,6 +15,10 @@ Then require the component you want to use in your application initializer. For
See specific files and folders inside the `lib/tire` folder for instructions and documentation.
+### Dynamic Persistence ###
+
+Adds support for dynamic attributes when using Tire::Model::Persistence so that model properties no longer need to be declared explicitly. [More info](lib/tire/model/dynamic_persistence).
+
### More Like This Queries ###
Adds support for [“more like this”](http://www.elasticsearch.org/guide/reference/query-dsl/mlt-query.html) queries.
View
34 lib/tire/model/dynamic_persistence.rb
@@ -0,0 +1,34 @@
+# Dynamic Persistence
+# ===================
+#
+# Author: Dave Kinkead <dave@kinkead.com.au>
+#
+#
+# Adds support for dynamic persistence to Tire::Model::Persistence so that explict
+# declarations of 'property :attr_name' are not required
+#
+#
+# Usage:
+# ------
+#
+# Require the component:
+#
+# require 'tire/model/dynamic_persistence'
+#
+# Example:
+# -------
+#
+# class Author
+#
+# include Tire::Model::Persistence
+# include Tire::Model::DynamicPersistence
+# end
+#
+# author = Author.new :name => 'Inigo Montoya',
+# :books => ['The Pragmatic Swordfighter', 'Revenge: Best Served Cold']
+#
+# author.name
+# # => 'Inigo Montoya'
+#
+#
+require 'tire/model/dynamic_persistence/dynamic_persistence'
View
28 lib/tire/model/dynamic_persistence/README.markdown
@@ -0,0 +1,28 @@
+# Dynamic Persistence
+
+Adds support for truly dynamic persistence models so that you no longer have to explicitly declare properties.
+
+Very useful if you want to create models on the fly.
+
+## Usage
+
+Require the module in your model file
+
+ require 'tire/model/dynamic_persistence'
+
+Include Persistence and DynamicPersistence
+
+ class Author
+
+ include Tire::Model::Persistence
+ include Tire::Model::DynamicPersistence
+ end
+
+Then create your model by passing it a hash of key:value pairs
+
+ author = Author.new :name => 'Inigo Montoya',
+ :books => ['The Pragmatic Swordfighter', 'Revenge: Best Served Cold']
+
+ author.name
+ # => 'Inigo Montoya'
+
View
21 lib/tire/model/dynamic_persistence/dynamic_persistence.rb
@@ -0,0 +1,21 @@
+require 'tire'
+
+module Tire
+ module Model
+ module DynamicPersistence
+
+ # Overrides the initializer in Tire::Model::Persistence to allow
+ # dynamic creation of attributes without the need to
+ # declare them with 'property :name'
+ def initialize(attrs={})
+ attrs.each do |attr, value|
+ # => call Tire's property method if it hasn't been set
+ self.class.property attr unless self.class.property_types.keys.include? attr
+ # => set instance variable
+ instance_variable_set("@#{attr}", value)
+ end
+ super attrs
+ end
+ end
+ end
+end
View
26 test/dynamic_persistence/dynamic_persistence_test.rb
@@ -0,0 +1,26 @@
+require 'test_helper'
+
+module Tire
+ module Model
+
+ class DynamicPersistenceTest < Test::Unit::TestCase
+
+ context "Persistent model with dynamic creation" do
+
+ should "permit access to attrs passed to create" do
+ @article = PersistentArticleWithDynamicCreation.new :name => 'Elasticsearch', :title => 'You know, for Search!'
+ assert_equal @article.name, 'Elasticsearch'
+ end
+
+ should "not override explicit persistent properties" do
+ @article = PersistentArticleWithDynamicCreation.new :name => 'Elasticsearch', :author => { :name => 'Inigo Montoya' }
+ assert_equal @article.author.name, 'Inigo Montoya'
+ assert_equal @article.tags.class, Array
+ assert_equal @article.tags.length, 0
+ end
+
+ end
+
+ end
+ end
+end
View
564 test/dynamic_persistence/model_persistence_test.rb
@@ -0,0 +1,564 @@
+require 'test_helper'
+
+module Tire
+ module Model
+
+ class PersistenceTest < Test::Unit::TestCase
+
+ context "Model" do
+
+ should "have default index name" do
+ assert_equal 'persistent_articles', PersistentArticle.index_name
+ assert_equal 'persistent_articles', PersistentArticle.new(:title => 'Test').index_name
+ end
+
+ should "allow to set custom index name" do
+ assert_equal 'custom-index-name', PersistentArticleWithCustomIndexName.index_name
+
+ PersistentArticleWithCustomIndexName.index_name "another-index-name"
+ assert_equal 'another-index-name', PersistentArticleWithCustomIndexName.index_name
+ assert_equal 'another-index-name', PersistentArticleWithCustomIndexName.index.name
+ end
+
+ context "with index prefix" do
+ setup do
+ Model::Search.index_prefix 'prefix'
+ end
+
+ teardown do
+ Model::Search.index_prefix nil
+ end
+
+ should "have configured prefix in index_name" do
+ assert_equal 'prefix_persistent_articles', PersistentArticle.index_name
+ assert_equal 'prefix_persistent_articles', PersistentArticle.new(:title => 'Test').index_name
+ end
+
+ end
+
+ should "have document_type" do
+ assert_equal 'persistent_article', PersistentArticle.document_type
+ assert_equal 'persistent_article', PersistentArticle.new(:title => 'Test').document_type
+ end
+
+ should "allow to define property" do
+ assert_nothing_raised do
+ a = PersistentArticle.new
+ class << a
+ property :status
+ end
+ end
+ end
+
+ end
+
+ context "Finders" do
+
+ setup do
+ @first = { '_id' => 1, '_version' => 1, '_index' => 'persistent_articles', '_type' => 'persistent_article', '_source' => { :title => 'First' } }
+ @second = { '_id' => 2, '_index' => 'persistent_articles', '_type' => 'persistent_article', '_source' => { :title => 'Second' } }
+ @third = { '_id' => 3, '_index' => 'persistent_articles', '_type' => 'persistent_article', '_source' => { :title => 'Third' } }
+ @find_all = { 'hits' => { 'hits' => [
+ @first,
+ @second,
+ @third
+ ] } }
+ @find_first = { 'hits' => { 'hits' => [ @first ] } }
+ @find_last_two = { 'hits' => { 'hits' => [ @second, @third ] } }
+ @find_twenty_ids = { 'hits' => { 'hits' => 20.times.map { @first } } }
+ end
+
+ should "find document by numeric ID" do
+ Configuration.client.expects(:get).returns(mock_response(@first.to_json))
+ document = PersistentArticle.find 1
+
+ assert_instance_of PersistentArticle, document
+ assert_equal 1, document.id
+ assert_equal 1, document.attributes['id']
+ assert_equal 'First', document.attributes['title']
+ assert_equal 'First', document.title
+ end
+
+ should "have _type, _index, _id, _version attributes" do
+ Configuration.client.expects(:get).returns(mock_response(@first.to_json))
+ document = PersistentArticle.find 1
+
+ assert_instance_of PersistentArticle, document
+ assert_equal 1, document.id
+ assert_equal 1, document.attributes['id']
+ assert_equal 'persistent_articles', document._index
+ assert_equal 'persistent_article', document._type
+ assert_equal 1, document._version
+ end
+
+ should "find document by string ID" do
+ Configuration.client.expects(:get).returns(mock_response(@first.to_json))
+ document = PersistentArticle.find '1'
+
+ assert_instance_of PersistentArticle, document
+ assert_equal 1, document.id
+ assert_equal 1, document.attributes['id']
+ assert_equal 'First', document.attributes['title']
+ assert_equal 'First', document.title
+ end
+
+ should "find document by list of IDs" do
+ Configuration.client.expects(:get).returns(mock_response(@find_last_two.to_json))
+ documents = PersistentArticle.find 2, 3
+
+ assert_equal 2, documents.count
+ end
+
+ should "find document by array of IDs" do
+ Configuration.client.expects(:get).returns(mock_response(@find_last_two.to_json))
+ documents = PersistentArticle.find [2, 3]
+
+ assert_equal 2, documents.count
+ end
+
+ should "find all documents listed in IDs array" do
+ ids = (1..20).to_a
+ Configuration.client.expects(:get).returns(mock_response(@find_twenty_ids.to_json))
+ Tire::Search::Search.any_instance.expects(:size).with(ids.size)
+
+ documents = PersistentArticle.find ids
+ assert_equal ids.size, documents.count
+ end
+
+ should "find all documents with correct type" do
+ Configuration.client.expects(:get).
+ with do |url,payload|
+ assert_equal "#{Configuration.url}/persistent_articles/persistent_article/_search", url
+ end.
+ times(3).
+ returns(mock_response(@find_all.to_json))
+ documents = PersistentArticle.all
+
+ assert_equal 3, documents.count
+ assert_equal 'First', documents.first.attributes['title']
+ assert_equal PersistentArticle.find(:all).map { |e| e.id }, PersistentArticle.all.map { |e| e.id }
+ end
+
+ should "find first document with correct type" do
+ Configuration.client.expects(:get).
+ with do |url,payload|
+ assert_equal "#{Configuration.url}/persistent_articles/persistent_article/_search?size=1", url
+ end.
+ returns(mock_response(@find_first.to_json))
+ document = PersistentArticle.first
+
+ assert_equal 'First', document.attributes['title']
+ end
+
+ should "raise error when passing incorrect argument" do
+ assert_raise(ArgumentError) do
+ PersistentArticle.find :name => 'Test'
+ end
+ end
+
+ should_eventually "raise error when document is not found" do
+ assert_raise(DocumentNotFound) do
+ PersistentArticle.find 'xyz001'
+ end
+ end
+
+ end
+
+ context "Persistent model" do
+
+ setup { @article = PersistentArticle.new :title => 'Test', :tags => [:one, :two] }
+
+ context "attribute methods" do
+
+ should "allow to set attributes on initialization" do
+ assert_not_nil @article.attributes
+ assert_equal 'Test', @article.attributes['title']
+ end
+
+ should "allow to leave attributes blank on initialization" do
+ assert_nothing_raised { PersistentArticle.new }
+ end
+
+ should "have getter methods for attributes" do
+ assert_not_nil @article.title
+ assert_equal 'Test', @article.title
+ assert_equal [:one, :two], @article.tags
+ end
+
+ should "have getter methods for attribute passed as a String" do
+ article = PersistentArticle.new 'title' => 'Tony Montana'
+ assert_not_nil article.title
+ assert_equal 'Tony Montana', article.title
+ end
+
+ should "raise error when getting unknown attribute" do
+ assert_raise(NoMethodError) do
+ @article.krapulitz
+ end
+ end
+
+ should "not raise error when getting unset attribute" do
+ article = PersistentArticle.new :title => 'Test'
+
+ assert_nothing_raised { article.published_on }
+ assert_nil article.published_on
+ end
+
+ should "return default value for attribute" do
+ article = PersistentArticleWithDefaults.new :title => 'Test'
+ assert_equal [], article.tags
+ assert_equal false, article.hidden
+ end
+
+ should "evaluate lambdas as default values" do
+ article = PersistentArticleWithDefaults.new
+ assert_equal Time.now.year, article.created_at.year
+ end
+
+ should "not affect default value" do
+ article = PersistentArticleWithDefaults.new :title => 'Test'
+ article.tags << "ruby"
+
+ article.options[:switches] << "switch_1"
+
+ assert_equal [], PersistentArticleWithDefaults.new.tags
+ assert_equal [], PersistentArticleWithDefaults.new.options[:switches]
+ end
+
+ should "have query method for attribute" do
+ assert_equal true, @article.title?
+ end
+
+ should "raise error when querying for unknown attribute" do
+ assert_raise(NoMethodError) do
+ @article.krapulitz?
+ end
+ end
+
+ should "not raise error when querying for unset attribute" do
+ article = PersistentArticle.new :title => 'Test'
+
+ assert_nothing_raised { article.published_on? }
+ assert ! article.published_on?
+ end
+
+ should "return true for respond_to? calls for set attributes" do
+ article = PersistentArticle.new :title => 'Test'
+ assert article.respond_to?(:title)
+ end
+
+ should "return false for respond_to? calls for unknown attributes" do
+ article = PersistentArticle.new :title => 'Test'
+ assert ! article.respond_to?(:krapulitz)
+ end
+
+ should "return true for respond_to? calls for defined but unset attributes" do
+ article = PersistentArticle.new :title => 'Test'
+
+ assert article.respond_to?(:published_on)
+ end
+
+ should "have attribute names" do
+ article = PersistentArticle.new :title => 'Test', :tags => ['one', 'two']
+ #
+ # Changed this test as DynamicPersistence accepts elasticsearch meta_attributes
+ # as attribute_names on creation.
+ #
+ # assert_equal ['published_on', 'tags', 'title'], article.attribute_names
+ #
+ assert_equal ["_explanation",
+ "_index",
+ "_score",
+ "_type",
+ "_version",
+ "highlight",
+ "id",
+ "published_on",
+ "sort",
+ "tags",
+ "title"], article.attribute_names
+ end
+
+ should "have setter method for attribute" do
+ @article.title = 'Updated'
+ assert_equal 'Updated', @article.title
+ assert_equal 'Updated', @article.attributes['title']
+ end
+
+ should_eventually "allow to set deeply nested attributes on initialization" do
+ article = PersistentArticle.new :title => 'Test', :author => { :first_name => 'John', :last_name => 'Smith' }
+
+ assert_equal 'John', article.author.first_name
+ assert_equal 'Smith', article.author.last_name
+ assert_equal({ :first_name => 'John', :last_name => 'Smith' }, article.attributes['author'])
+ end
+
+ should_eventually "allow to set deeply nested attributes on update" do
+ article = PersistentArticle.new :title => 'Test', :author => { :first_name => 'John', :last_name => 'Smith' }
+
+ article.author.first_name = 'Robert'
+ article.author.last_name = 'Carpenter'
+
+ assert_equal 'Robert', article.author.first_name
+ assert_equal 'Carpenter', article.author.last_name
+ assert_equal({ :first_name => 'Robert', :last_name => 'Carpenter' }, article.attributes['author'])
+ end
+
+ end
+
+ context "with casting" do
+
+ should "cast the value as custom class" do
+ article = PersistentArticleWithCastedItem.new :title => 'Test',
+ :author => { :first_name => 'John', :last_name => 'Smith' }
+ assert_instance_of Author, article.author
+ assert_equal 'John', article.author.first_name
+ end
+
+ should "cast the value as collection of custom classes" do
+ article = PersistentArticleWithCastedCollection.new :title => 'Test',
+ :comments => [{:nick => '4chan', :body => 'WHY U NO?'}]
+ assert_instance_of Array, article.comments
+ assert_instance_of Comment, article.comments.first
+ assert_equal '4chan', article.comments.first.nick
+ end
+
+ should "automatically format strings in UTC format as Time" do
+ article = PersistentArticle.new :published_on => '2011-11-01T23:00:00Z'
+ assert_instance_of Time, article.published_on
+ assert_equal 2011, article.published_on.year
+ end
+
+ should "cast anonymous Hashes as Hashr instances" do
+ article = PersistentArticleWithCastedItem.new :stats => { :views => 100, :meta => { :tags => 'A' } }
+ assert_equal 100, article.stats.views
+ assert_equal 'A', article.stats.meta.tags
+ end
+
+ should "create empty collection for missing value" do
+ article = PersistentArticleWithCastedCollection.new :title => 'Test'
+ assert_respond_to article.comments, :each
+ assert article.comments.empty?, "article.comments should be empty: " + article.inspect
+ end
+
+ end
+
+ context "when initializing" do
+
+ should "be a new record" do
+ article = PersistentArticle.new :title => 'Test'
+
+ assert article.new_record?, "#{article.inspect} should be `new_record?`"
+ assert ! article.persisted?, "#{article.inspect} should NOT be `persisted?`"
+ end
+
+ end
+
+ context "when creating" do
+
+ should "save the document with generated ID in the database" do
+ Configuration.client.expects(:post).
+ with do |url, payload|
+ doc = MultiJson.decode(payload)
+ url == "#{Configuration.url}/persistent_articles/persistent_article/" &&
+ doc['title'] == 'Test' &&
+ doc['tags'] == ['one', 'two']
+ doc['published_on'] == nil
+ end.
+ returns(mock_response('{"ok":true,"_id":"abc123","_version":1}'))
+ article = PersistentArticle.create :title => 'Test', :tags => [:one, :two]
+
+ assert article.persisted?, "#{article.inspect} should be `persisted?`"
+ assert ! article.new_record?, "#{article.inspect} should NOT be `new_record?`"
+ assert_equal 'abc123', article.id
+ end
+
+ should "save the document with custom ID in the database" do
+ Configuration.client.expects(:post).
+ with do |url, payload|
+ doc = MultiJson.decode(payload)
+ url == "#{Configuration.url}/persistent_articles/persistent_article/r2d2" &&
+ doc['title'] == 'Test' &&
+ doc['published_on'] == nil
+ end.
+ returns(mock_response('{"ok":true,"_id":"r2d2"}'))
+ article = PersistentArticle.create :id => 'r2d2', :title => 'Test'
+
+ assert_equal 'r2d2', article.id
+ end
+
+ should "perform model validations" do
+ Configuration.client.expects(:post).never
+
+ assert ! ValidatedModel.create(:name => nil)
+ end
+
+ end
+
+ context "when creating" do
+
+ should "set the id property" do
+ Configuration.client.expects(:post).
+ with do |url, payload|
+ doc = MultiJson.decode(payload)
+ url == "#{Configuration.url}/persistent_articles/persistent_article/" &&
+ doc['title'] == 'Test'
+ end.
+ returns(mock_response('{"ok":true,"_id":"1"}'))
+
+ article = PersistentArticle.create :title => 'Test'
+ assert_equal '1', article.id
+ end
+
+ should "not set the id property if already set" do
+ Configuration.client.expects(:post).
+ with do |url, payload|
+ doc = MultiJson.decode(payload)
+ url == "#{Configuration.url}/persistent_articles/persistent_article/123" &&
+ doc['title'] == 'Test' &&
+ doc['published_on'] == nil
+ end.
+ returns(mock_response('{"ok":true, "_id":"XXX"}'))
+
+ article = PersistentArticle.create :id => '123', :title => 'Test'
+ assert_equal '123', article.id
+ end
+
+ end
+
+ context "when saving" do
+
+ should "save the document with updated attribute" do
+ article = PersistentArticle.new :id => '1', :title => 'Test'
+
+ Configuration.client.expects(:post).
+ with do |url, payload|
+ doc = MultiJson.decode(payload)
+ url == "#{Configuration.url}/persistent_articles/persistent_article/1" &&
+ doc['title'] == 'Test' &&
+ doc['published_on'] == nil
+ end.
+ returns(mock_response('{"ok":true,"_id":"1"}'))
+ assert article.save
+
+ article.title = 'Updated'
+
+ Configuration.client.expects(:post).
+ with do |url, payload|
+ doc = MultiJson.decode(payload)
+ url == "#{Configuration.url}/persistent_articles/persistent_article/1" &&
+ doc['title'] == 'Updated'
+ end.
+ returns(mock_response('{"ok":true,"_id":"1"}'))
+ assert article.save
+ end
+
+ should "perform validations" do
+ article = ValidatedModel.new :name => nil
+ assert ! article.save
+ end
+
+ should "set the id property itself" do
+ article = PersistentArticle.new
+ article.title = 'Test'
+
+ Configuration.client.expects(:post).with("#{Configuration.url}/persistent_articles/persistent_article/",
+ article.to_indexed_json).
+ returns(mock_response('{"ok":true,"_id":"1"}'))
+ assert article.save
+ assert_equal '1', article.id
+ end
+
+ should "not set the id property if already set" do
+ article = PersistentArticle.new
+ article.id = '456'
+ article.title = 'Test'
+
+ Configuration.client.expects(:post).
+ with do |url, payload|
+ doc = MultiJson.decode(payload)
+ url == "#{Configuration.url}/persistent_articles/persistent_article/456" &&
+ doc['title'] == 'Test'
+ end.
+ returns(mock_response('{"ok":true,"_id":"XXX"}'))
+ assert article.save
+ assert_equal '456', article.id
+ end
+
+ end
+
+ context "when destroying" do
+
+ should "delete the document from the database" do
+ Configuration.client.expects(:post).
+ with do |url, payload|
+ doc = MultiJson.decode(payload)
+ url == "#{Configuration.url}/persistent_articles/persistent_article/123" &&
+ doc['title'] == 'Test'
+ end.returns(mock_response('{"ok":true,"_id":"123"}'))
+
+ Configuration.client.expects(:delete).
+ with("#{Configuration.url}/persistent_articles/persistent_article/123").
+ returns(mock_response('{"ok":true,"acknowledged":true}', 200))
+
+ article = PersistentArticle.new :id => '123', :title => 'Test'
+ article.save
+ article.destroy
+ end
+
+ end
+
+ context "when updating attributes" do
+
+ should "update single attribute" do
+ @article.expects(:save).returns(true)
+
+ @article.update_attribute :title, 'Updated'
+ assert_equal 'Updated', @article.title
+ end
+
+ should "update all attributes" do
+ @article.expects(:save).returns(true)
+
+ @article.update_attributes :title => 'Updated', :tags => ['three']
+ assert_equal 'Updated', @article.title
+ assert_equal ['three'], @article.tags
+ end
+
+ end
+
+ end
+
+ context "Persistent model with mapping definition" do
+
+ should "create the index with mapping" do
+ expected = {
+ :settings => {},
+ :mappings => { :persistent_article_with_mapping => {
+ :properties => { :title => { :type => 'string', :analyzer => 'snowball', :boost => 10 } }
+ }}
+ }
+
+ Tire::Index.any_instance.stubs(:exists?).returns(false)
+ Tire::Index.any_instance.expects(:create).with(expected)
+
+ class ::PersistentArticleWithMapping
+
+ include Tire::Model::Persistence
+ include Tire::Model::Search
+ include Tire::Model::Callbacks
+
+ mapping do
+ property :title, :type => 'string', :analyzer => 'snowball', :boost => 10
+ end
+
+ end
+
+ assert_equal 'snowball', PersistentArticleWithMapping.mapping[:title][:analyzer]
+ end
+
+ end
+
+ end
+ end
+end
View
13 test/dynamic_persistence/models/persistent_article.rb
@@ -0,0 +1,13 @@
+# Example class with Elasticsearch persistence
+require 'tire/model/dynamic_persistence'
+
+class PersistentArticle
+
+ include Tire::Model::Persistence
+ include Tire::Model::DynamicPersistence
+
+ property :title
+ property :published_on
+ property :tags
+
+end
View
18 test/dynamic_persistence/models/persistent_article_in_index.rb
@@ -0,0 +1,18 @@
+# Example class with Elasticsearch persistence in index `persistent_articles`
+#
+# The `index` is `persistent_articles`
+#
+require 'tire/model/dynamic_persistence'
+
+class PersistentArticleInIndex
+
+ include Tire::Model::Persistence
+ include Tire::Model::DynamicPersistence
+
+ property :title
+ property :published_on
+ property :tags
+
+ index_name "persistent_articles"
+
+end
View
15 test/dynamic_persistence/models/persistent_article_in_namespace.rb
@@ -0,0 +1,15 @@
+# Example namespaced class with Elasticsearch persistence
+#
+# The `document_type` is `my_namespace/persistent_article_in_namespace`
+#
+require 'tire/model/dynamic_persistence'
+
+module MyNamespace
+ class PersistentArticleInNamespace
+
+ include Tire::Model::Persistence
+ include Tire::Model::DynamicPersistence
+
+ property :title
+ end
+end
View
32 test/dynamic_persistence/models/persistent_article_with_casting.rb
@@ -0,0 +1,32 @@
+require 'tire/model/dynamic_persistence'
+
+class Author
+ attr_accessor :first_name, :last_name
+ def initialize(attributes)
+ @first_name = HashWithIndifferentAccess.new(attributes)[:first_name]
+ @last_name = HashWithIndifferentAccess.new(attributes)[:last_name]
+ end
+end
+
+class Comment
+ def initialize(params); @attributes = HashWithIndifferentAccess.new(params); end
+ def method_missing(method_name, *arguments); @attributes[method_name]; end
+ def as_json(*); @attributes; end
+end
+
+class PersistentArticleWithCastedItem
+ include Tire::Model::Persistence
+ include Tire::Model::DynamicPersistence
+
+ property :title
+ property :author, :class => Author
+ property :stats
+end
+
+class PersistentArticleWithCastedCollection
+ include Tire::Model::Persistence
+ include Tire::Model::DynamicPersistence
+
+ property :title
+ property :comments, :class => [Comment]
+end
View
15 test/dynamic_persistence/models/persistent_article_with_defaults.rb
@@ -0,0 +1,15 @@
+require 'tire/model/dynamic_persistence'
+
+class PersistentArticleWithDefaults
+
+ include Tire::Model::Persistence
+ include Tire::Model::DynamicPersistence
+
+ property :title
+ property :published_on
+ property :tags, :default => []
+ property :hidden, :default => false
+ property :options, :default => {:switches => []}
+ property :created_at, :default => lambda { Time.now }
+
+end
View
12 test/dynamic_persistence/models/persistent_articles_with_custom_index_name.rb
@@ -0,0 +1,12 @@
+# Example class with Elasticsearch persistence and custom index name
+require 'tire/model/dynamic_persistence'
+
+class PersistentArticleWithCustomIndexName
+
+ include Tire::Model::Persistence
+ include Tire::Model::DynamicPersistence
+
+ property :title
+
+ index_name 'custom-index-name'
+end
View
17 test/dynamic_persistence/models/persistent_articles_with_dynamic_attributes.rb
@@ -0,0 +1,17 @@
+# Example class with Elasticsearch persistence
+require 'tire/model/dynamic_persistence'
+
+class DynamicAuthor
+
+ include Tire::Model::Persistence
+ include Tire::Model::DynamicPersistence
+end
+
+class PersistentArticleWithDynamicCreation
+
+ include Tire::Model::Persistence
+ include Tire::Model::DynamicPersistence
+
+ property :author, :class => DynamicAuthor
+ property :tags, :default => []
+end
View
13 test/dynamic_persistence/models/validated_model.rb
@@ -0,0 +1,13 @@
+# Example ActiveModel with validations
+require 'tire/model/dynamic_persistence'
+
+class ValidatedModel
+
+ include Tire::Model::Persistence
+ include Tire::Model::DynamicPersistence
+
+ property :name
+
+ validates_presence_of :name
+
+end
View
15 test/test_helper.rb
@@ -1,14 +1,23 @@
require 'rubygems'
-
require 'pathname'
require 'test/unit'
-
require 'shoulda'
require 'turn' unless ENV["TM_FILEPATH"] || ENV["CI"]
require 'mocha'
-
+require 'active_support/core_ext/hash/indifferent_access'
require 'tire'
+# => Require models for testing
+require File.dirname(__FILE__) + '/dynamic_persistence/models/validated_model'
+require File.dirname(__FILE__) + '/dynamic_persistence/models/persistent_article'
+require File.dirname(__FILE__) + '/dynamic_persistence/models/persistent_article_in_index'
+require File.dirname(__FILE__) + '/dynamic_persistence/models/persistent_article_in_namespace'
+require File.dirname(__FILE__) + '/dynamic_persistence/models/persistent_article_with_casting'
+require File.dirname(__FILE__) + '/dynamic_persistence/models/persistent_article_with_defaults'
+require File.dirname(__FILE__) + '/dynamic_persistence/models/persistent_articles_with_custom_index_name'
+require File.dirname(__FILE__) + '/dynamic_persistence/models/persistent_articles_with_dynamic_attributes'
+
+
class Test::Unit::TestCase
def mock_response(body, code=200, headers={})
View
4 tire-contrib.gemspec
@@ -6,8 +6,8 @@ Gem::Specification.new do |s|
s.name = "tire-contrib"
s.version = Tire::Contrib::VERSION
s.platform = Gem::Platform::RUBY
- s.authors = ["Karel Minarik", "Oliver Eilhard"]
- s.email = ["karmi@karmi.cz", "oliver.eilhard@gmail.com"]
+ s.authors = ["Karel Minarik", "Oliver Eilhard", "Dave Kinkead"]
+ s.email = ["karmi@karmi.cz", "oliver.eilhard@gmail.com", "dave@kinkead.com.au"]
s.homepage = ""
s.summary = %q{Contributions and additions for the Tire gem}
Please sign in to comment.
Something went wrong with that request. Please try again.