plyushkin 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +58 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/plyushkin.rb +15 -0
- data/lib/plyushkin/base_value.rb +59 -0
- data/lib/plyushkin/core_ext/active_record_base.rb +27 -0
- data/lib/plyushkin/core_ext/plyushkin_extensions.rb +26 -0
- data/lib/plyushkin/model.rb +35 -0
- data/lib/plyushkin/nil_value.rb +9 -0
- data/lib/plyushkin/persistence.rb +50 -0
- data/lib/plyushkin/property.rb +76 -0
- data/lib/plyushkin/service.rb +3 -0
- data/lib/plyushkin/service/stub.rb +15 -0
- data/lib/plyushkin/string_value.rb +3 -0
- data/lib/plyushkin/test.rb +1 -0
- data/lib/plyushkin/test/value_types.rb +17 -0
- data/lib/plyushkin/validators/presence.rb +5 -0
- data/lib/plyushkin/version.rb +3 -0
- data/plyushkin.gemspec +25 -0
- data/spec/lib/base_value_spec.rb +128 -0
- data/spec/lib/core_ext/active_record_base_spec.rb +160 -0
- data/spec/lib/nil_value_spec.rb +11 -0
- data/spec/lib/persistence_spec.rb +79 -0
- data/spec/lib/property_spec.rb +136 -0
- data/spec/lib/value_spec.rb +30 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/support/sqlite.rb +12 -0
- metadata +135 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
plyushkin (0.0.1)
|
5
|
+
activerecord (~> 3.2.12)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activemodel (3.2.16)
|
11
|
+
activesupport (= 3.2.16)
|
12
|
+
builder (~> 3.0.0)
|
13
|
+
activerecord (3.2.16)
|
14
|
+
activemodel (= 3.2.16)
|
15
|
+
activesupport (= 3.2.16)
|
16
|
+
arel (~> 3.0.2)
|
17
|
+
tzinfo (~> 0.3.29)
|
18
|
+
activesupport (3.2.16)
|
19
|
+
i18n (~> 0.6, >= 0.6.4)
|
20
|
+
multi_json (~> 1.0)
|
21
|
+
arel (3.0.3)
|
22
|
+
builder (3.0.4)
|
23
|
+
coderay (1.1.0)
|
24
|
+
diff-lcs (1.2.5)
|
25
|
+
i18n (0.6.9)
|
26
|
+
method_source (0.8.2)
|
27
|
+
multi_json (1.8.4)
|
28
|
+
pry (0.9.12.4)
|
29
|
+
coderay (~> 1.0)
|
30
|
+
method_source (~> 0.8)
|
31
|
+
slop (~> 3.4)
|
32
|
+
pry-nav (0.2.3)
|
33
|
+
pry (~> 0.9.10)
|
34
|
+
rake (10.1.1)
|
35
|
+
rspec (2.14.1)
|
36
|
+
rspec-core (~> 2.14.0)
|
37
|
+
rspec-expectations (~> 2.14.0)
|
38
|
+
rspec-mocks (~> 2.14.0)
|
39
|
+
rspec-core (2.14.7)
|
40
|
+
rspec-expectations (2.14.4)
|
41
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
42
|
+
rspec-mocks (2.14.4)
|
43
|
+
slop (3.4.7)
|
44
|
+
sqlite3 (1.3.8)
|
45
|
+
timecop (0.7.1)
|
46
|
+
tzinfo (0.3.38)
|
47
|
+
|
48
|
+
PLATFORMS
|
49
|
+
ruby
|
50
|
+
|
51
|
+
DEPENDENCIES
|
52
|
+
bundler (~> 1.3)
|
53
|
+
plyushkin!
|
54
|
+
pry-nav
|
55
|
+
rake
|
56
|
+
rspec
|
57
|
+
sqlite3
|
58
|
+
timecop
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Craig Israel
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Plyushkin
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'plyushkin'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install plyushkin
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/plyushkin.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "plyushkin/version"
|
2
|
+
require "active_record"
|
3
|
+
|
4
|
+
module Plyushkin; end
|
5
|
+
path = File.dirname(File.expand_path(__FILE__))
|
6
|
+
require path + "/plyushkin/base_value"
|
7
|
+
require path + "/plyushkin/string_value"
|
8
|
+
require path + "/plyushkin/nil_value"
|
9
|
+
require path + "/plyushkin/property"
|
10
|
+
require path + "/plyushkin/model"
|
11
|
+
require path + "/plyushkin/service"
|
12
|
+
require path + "/plyushkin/persistence"
|
13
|
+
require path + "/plyushkin/validators/presence"
|
14
|
+
require path + "/plyushkin/core_ext/plyushkin_extensions"
|
15
|
+
require path + "/plyushkin/core_ext/active_record_base"
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class Plyushkin::BaseValue
|
2
|
+
include ActiveModel::Validations
|
3
|
+
|
4
|
+
def initialize(attr={})
|
5
|
+
attr = attr.dup
|
6
|
+
@date = attr.delete(:date) || DateTime.current
|
7
|
+
attr.each do |k,v|
|
8
|
+
send("#{k}=", v) if respond_to?("#{k}=")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.persisted_attr(*attributes)
|
13
|
+
opts = attributes.last.is_a?(Hash) ? attributes.pop : {}
|
14
|
+
names = attributes
|
15
|
+
formatter = opts[:formatter]
|
16
|
+
|
17
|
+
persisted_attributes.concat(names)
|
18
|
+
attr_writer *names
|
19
|
+
names.each do |name|
|
20
|
+
define_method(name) do
|
21
|
+
value = instance_variable_get("@#{name}")
|
22
|
+
if formatter
|
23
|
+
send(formatter, value)
|
24
|
+
else
|
25
|
+
value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.persisted_attributes
|
32
|
+
if self.superclass == Object
|
33
|
+
@persisted_attributes ||= []
|
34
|
+
else
|
35
|
+
@persisted_attributes ||= superclass.persisted_attributes.dup
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
persisted_attr :date
|
40
|
+
validates_each :date do |record, attr_name, value|
|
41
|
+
record.errors.add(attr_name, "cannot be in the future") unless value < DateTime.now
|
42
|
+
end
|
43
|
+
|
44
|
+
def equal_value?(other)
|
45
|
+
self.class.persisted_attributes.each do |attribute|
|
46
|
+
return false if attribute != :date && send(attribute) != other.send(attribute)
|
47
|
+
end
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_i(value)
|
52
|
+
value.to_i
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_date(value)
|
56
|
+
value.is_a?(String) ? DateTime.parse(value) : value
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
ActiveRecord::Base.instance_eval do
|
2
|
+
def hoards(name, opts = {})
|
3
|
+
initialize_plyushkin
|
4
|
+
|
5
|
+
define_method(name) do
|
6
|
+
plyushkin.properties[name]
|
7
|
+
end
|
8
|
+
validates name, :plyushkin => true
|
9
|
+
|
10
|
+
plyushkin_model.register(name, opts[:type], opts)
|
11
|
+
plyushkin_model.register_callback(name, :after_create, opts[:after_create]) if opts[:after_create]
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize_plyushkin
|
15
|
+
class << self
|
16
|
+
def plyushkin_model
|
17
|
+
@plyushkin_model ||= Plyushkin::Model.new(Plyushkin::Service::Stub.new)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
include PlyushkinExtensions
|
22
|
+
|
23
|
+
after_initialize :load_plyushkin
|
24
|
+
after_save :save_plyushkin
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module PlyushkinExtensions
|
2
|
+
def reload(options=nil)
|
3
|
+
plyushkin.load(id)
|
4
|
+
super
|
5
|
+
end
|
6
|
+
|
7
|
+
def plyushkin
|
8
|
+
@plyushkin ||= Plyushkin::Persistence.new(self.class.plyushkin_model)
|
9
|
+
end
|
10
|
+
|
11
|
+
def load_plyushkin
|
12
|
+
self.class.plyushkin_model.callbacks.each do |name,callbacks|
|
13
|
+
callbacks.each do |callback, handler|
|
14
|
+
plyushkin.register_callback(name, callback) do
|
15
|
+
(handler && handler.is_a?(Symbol)) ? send(handler) : handler.call
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
plyushkin.load(id)
|
21
|
+
end
|
22
|
+
|
23
|
+
def save_plyushkin
|
24
|
+
plyushkin.save(id)
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Plyushkin::Model
|
2
|
+
|
3
|
+
def initialize(service)
|
4
|
+
@service = service
|
5
|
+
@types = {}
|
6
|
+
@ignore_unchanged_values = {}
|
7
|
+
@callbacks = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def register(name, type, opts={})
|
11
|
+
@types[name] = type
|
12
|
+
@ignore_unchanged_values[name] = opts[:ignore_unchanged_values]
|
13
|
+
end
|
14
|
+
|
15
|
+
def register_callback(name, callback, method_sym)
|
16
|
+
@callbacks[name] = { callback => method_sym }
|
17
|
+
end
|
18
|
+
|
19
|
+
def registered_types
|
20
|
+
@types.dup
|
21
|
+
end
|
22
|
+
|
23
|
+
def callbacks
|
24
|
+
@callbacks.dup
|
25
|
+
end
|
26
|
+
|
27
|
+
def ignore_unchanged_values
|
28
|
+
@ignore_unchanged_values.dup
|
29
|
+
end
|
30
|
+
|
31
|
+
def service
|
32
|
+
@service
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Plyushkin::Persistence
|
2
|
+
|
3
|
+
def initialize(model)
|
4
|
+
@model = model
|
5
|
+
@callbacks = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def properties
|
9
|
+
@properties
|
10
|
+
end
|
11
|
+
|
12
|
+
def save(id)
|
13
|
+
hash = {}
|
14
|
+
(@properties || {}).each do |name, property|
|
15
|
+
hash[name] = [property.value_hashes]
|
16
|
+
end
|
17
|
+
model.service.put(id, hash.to_json)
|
18
|
+
end
|
19
|
+
|
20
|
+
def load(id)
|
21
|
+
@properties = {}
|
22
|
+
model.service.get(id).each do |name, values|
|
23
|
+
property = Plyushkin::Property.build(name, model.registered_types[name.to_sym], values,
|
24
|
+
:callbacks => @callbacks[name.to_sym],
|
25
|
+
:ignore_unchanged_values => @model.ignore_unchanged_values[name.to_sym] )
|
26
|
+
@properties[name.to_sym] = property
|
27
|
+
end
|
28
|
+
add_missing_properties
|
29
|
+
end
|
30
|
+
|
31
|
+
def register_callback(name, callback, &block)
|
32
|
+
@callbacks[name] = { callback => block }
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def model
|
37
|
+
@model
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_missing_properties
|
41
|
+
(model.registered_types.keys - @properties.keys).each do |name|
|
42
|
+
property = Plyushkin::Property.new(name,
|
43
|
+
:type => model.registered_types[name],
|
44
|
+
:callbacks => @callbacks[name],
|
45
|
+
:ignore_unchanged_values => @model.ignore_unchanged_values[name])
|
46
|
+
@properties[name] = property
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
class Plyushkin::Property
|
2
|
+
include ActiveModel::Validations
|
3
|
+
|
4
|
+
DEFAULT_CALLBACK = lambda{}
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
validate do |property|
|
9
|
+
last.errors.full_messages.each do |message|
|
10
|
+
errors[:base] << "#{name.camelize}: #{message}"
|
11
|
+
end unless last.valid?
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(name, opts={})
|
15
|
+
@values = []
|
16
|
+
@value_type = opts[:type]
|
17
|
+
@callbacks = opts[:callbacks]
|
18
|
+
@ignore_unchanged_values = opts[:ignore_unchanged_values]
|
19
|
+
@name = name.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def create(attr={})
|
23
|
+
value = value_type.new(attr)
|
24
|
+
if @ignore_unchanged_values
|
25
|
+
last = @values.last
|
26
|
+
return last if last && last.equal_value?(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
@values.insert(insert_position(value.date), value)
|
30
|
+
trigger_callback(:after_create)
|
31
|
+
value
|
32
|
+
end
|
33
|
+
|
34
|
+
def trigger_callback(sym)
|
35
|
+
@callbacks.fetch(sym, DEFAULT_CALLBACK).call if @callbacks
|
36
|
+
end
|
37
|
+
|
38
|
+
def all
|
39
|
+
@values
|
40
|
+
end
|
41
|
+
|
42
|
+
def last
|
43
|
+
@values.last || Plyushkin::NilValue.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def empty?
|
47
|
+
@values.empty?
|
48
|
+
end
|
49
|
+
|
50
|
+
def insert_position(datetime)
|
51
|
+
index = @values.rindex{|v| v.date < datetime}
|
52
|
+
index.nil? ? 0 : index + 1
|
53
|
+
end
|
54
|
+
|
55
|
+
def value_type
|
56
|
+
@value_type ||= Plyushkin::StringValue
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.build(name, type, values, opts={})
|
60
|
+
opts[:type] = type
|
61
|
+
Plyushkin::Property.new(name, opts).tap do |p|
|
62
|
+
values.each { |value| p.create(value) }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def value_hashes
|
67
|
+
value_hashes = {}
|
68
|
+
all.each do |value|
|
69
|
+
value_type.persisted_attributes.each do |attr|
|
70
|
+
value_hashes[attr] = value.send(attr)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
value_hashes
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(File.expand_path(__FILE__)) + "/test/value_types.rb"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Plyushkin::Test
|
2
|
+
class Plyushkin::Test::PresenceTestValue < Plyushkin::BaseValue
|
3
|
+
persisted_attr :value
|
4
|
+
validates :value, :presence => true
|
5
|
+
end
|
6
|
+
|
7
|
+
class Plyushkin::Test::CoordinateValue < Plyushkin::BaseValue
|
8
|
+
persisted_attr :x, :y
|
9
|
+
validates :x, :y, :presence => true
|
10
|
+
end
|
11
|
+
|
12
|
+
class Plyushkin::Test::Member < ActiveRecord::Base; end
|
13
|
+
|
14
|
+
class Plyushkin::Test::DateValue < Plyushkin::BaseValue
|
15
|
+
persisted_attr :value, :formatter => :to_date
|
16
|
+
end
|
17
|
+
end
|
data/plyushkin.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'plyushkin/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "plyushkin"
|
8
|
+
spec.version = Plyushkin::VERSION
|
9
|
+
spec.authors = ["Craig Israel", "Jeremy Hinkle"]
|
10
|
+
spec.email = ["craig@theisraels.net", "jchinkle@gmail.com"]
|
11
|
+
spec.description = %q{Provides active record extension to capture historical property data}
|
12
|
+
spec.summary = %q{Plyushkin - the attribute hoarder}
|
13
|
+
spec.homepage = "http://github.com/OnlifeHealth/plyushkin"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "activerecord", "~> 3.2.12"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Plyushkin::BaseValue do
|
4
|
+
describe '#valid?' do
|
5
|
+
it 'should not be valid user-defined value if validations fail' do
|
6
|
+
value = Plyushkin::Test::CoordinateValue.new
|
7
|
+
value.valid?
|
8
|
+
value.errors.count.should == 2
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should be valid user-defined value if validations pass' do
|
12
|
+
value = Plyushkin::Test::CoordinateValue.new(:x => 5, :y => 10)
|
13
|
+
value.valid?
|
14
|
+
value.errors.count.should == 0
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should not be valid if date is in the future' do
|
18
|
+
value = Plyushkin::StringValue.new(:date => 2.days.from_now)
|
19
|
+
value.should_not be_valid
|
20
|
+
value.errors.full_messages.should == ["Date cannot be in the future"]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '##persisted_attr' do
|
25
|
+
it 'should add attribute to persisted_attributes' do
|
26
|
+
clazz = Class.new(Plyushkin::BaseValue) do
|
27
|
+
persisted_attr :my_attr
|
28
|
+
end
|
29
|
+
|
30
|
+
clazz.persisted_attributes.should == [ :date, :my_attr ]
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should add attributes to persisted_attributes when called multiple times' do
|
34
|
+
clazz = Class.new(Plyushkin::BaseValue) do
|
35
|
+
persisted_attr :my_attr
|
36
|
+
persisted_attr :my_other_attr
|
37
|
+
end
|
38
|
+
|
39
|
+
clazz.persisted_attributes.should == [ :date, :my_attr, :my_other_attr ]
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should add attributes to persisted_attributes when called with multiple attributes' do
|
43
|
+
clazz = Class.new(Plyushkin::BaseValue) do
|
44
|
+
persisted_attr :my_attr, :my_other_attr
|
45
|
+
end
|
46
|
+
|
47
|
+
clazz.persisted_attributes.should == [ :date, :my_attr, :my_other_attr ]
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should add reader and writer for attribute' do
|
51
|
+
clazz = Class.new(Plyushkin::BaseValue) do
|
52
|
+
persisted_attr :my_attr
|
53
|
+
end
|
54
|
+
|
55
|
+
value = clazz.new
|
56
|
+
value.my_attr = 5
|
57
|
+
value.my_attr.should == 5
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should format value readers using format methods when specified" do
|
61
|
+
clazz = Class.new(Plyushkin::BaseValue) do
|
62
|
+
persisted_attr :my_attr, :formatter => :to_i
|
63
|
+
end
|
64
|
+
|
65
|
+
value = clazz.new
|
66
|
+
value.my_attr = "5"
|
67
|
+
value.my_attr.should == 5
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should format multiple value readers using format methods when specified" do
|
71
|
+
clazz = Class.new(Plyushkin::BaseValue) do
|
72
|
+
persisted_attr :my_attr, :my_attr2, :formatter => :to_i
|
73
|
+
end
|
74
|
+
|
75
|
+
value = clazz.new
|
76
|
+
value.my_attr = "5"
|
77
|
+
value.my_attr2 = "9999"
|
78
|
+
value.my_attr.should == 5
|
79
|
+
value.my_attr2.should == 9999
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#to_date' do
|
83
|
+
it 'format a json string to a date' do
|
84
|
+
value = Plyushkin::BaseValue.new
|
85
|
+
now = DateTime.now
|
86
|
+
value.to_date(now.to_json).should === now
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#equal_value' do
|
93
|
+
it 'should test equality of persisted_attributes' do
|
94
|
+
clazz = Class.new(Plyushkin::BaseValue) do
|
95
|
+
persisted_attr :my_attr, :my_attr2
|
96
|
+
end
|
97
|
+
|
98
|
+
value1 = clazz.new
|
99
|
+
value1.my_attr = 5
|
100
|
+
value1.my_attr2 = "test"
|
101
|
+
|
102
|
+
value2 = clazz.new
|
103
|
+
value2.my_attr = 5
|
104
|
+
value2.my_attr2 = "test"
|
105
|
+
|
106
|
+
value1.equal_value?(value2).should be_true
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should be true if dates are different' do
|
110
|
+
clazz = Class.new(Plyushkin::BaseValue) do
|
111
|
+
persisted_attr :my_attr, :my_attr2
|
112
|
+
end
|
113
|
+
|
114
|
+
value1 = clazz.new
|
115
|
+
value1.my_attr = 5
|
116
|
+
value1.my_attr2 = "test"
|
117
|
+
value1.date = DateTime.now - 3.days
|
118
|
+
|
119
|
+
value2 = clazz.new
|
120
|
+
value2.my_attr = 5
|
121
|
+
value2.my_attr2 = "test"
|
122
|
+
value2.date = DateTime.now - 5.days
|
123
|
+
|
124
|
+
value1.equal_value?(value2).should be_true
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveRecord::Base do
|
4
|
+
describe '##hoards' do
|
5
|
+
describe 'read' do
|
6
|
+
it 'should return the same property instance when called multiple times' do
|
7
|
+
clazz = Class.new(Plyushkin::Test::Member) do
|
8
|
+
hoards :login_date
|
9
|
+
end
|
10
|
+
|
11
|
+
member = clazz.new
|
12
|
+
property = member.login_date
|
13
|
+
property.class.should == Plyushkin::Property
|
14
|
+
property.should == member.login_date
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should register a type for a hoarding property with persistence class' do
|
18
|
+
clazz = Class.new(Plyushkin::Test::Member) do
|
19
|
+
hoards :login_date
|
20
|
+
hoards :geolocation, :type => Plyushkin::Test::CoordinateValue
|
21
|
+
end
|
22
|
+
|
23
|
+
clazz.plyushkin_model.registered_types[:login_date].should be_nil
|
24
|
+
clazz.plyushkin_model.registered_types[:geolocation].should == Plyushkin::Test::CoordinateValue
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should allow specifying value type' do
|
28
|
+
clazz = Class.new(Plyushkin::Test::Member) do
|
29
|
+
hoards :geolocation, :type => Plyushkin::Test::CoordinateValue
|
30
|
+
end
|
31
|
+
|
32
|
+
member = clazz.new
|
33
|
+
property = member.geolocation
|
34
|
+
property.value_type.should == Plyushkin::Test::CoordinateValue
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'after_create option' do
|
39
|
+
it 'should call method specified by option after property create is called' do
|
40
|
+
clazz = Class.new(Plyushkin::Test::Member) do
|
41
|
+
attr_accessor :login_date_created_called
|
42
|
+
hoards :login_date, :after_create => :login_date_created
|
43
|
+
|
44
|
+
def login_date_created
|
45
|
+
self.login_date_created_called = true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
member = clazz.new
|
50
|
+
member.login_date.create :value => DateTime.now
|
51
|
+
member.login_date_created_called.should be_true
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should call method specified by option after property create is called for the property named' do
|
55
|
+
clazz = Class.new(Plyushkin::Test::Member) do
|
56
|
+
attr_accessor :login_date_created_called, :other_prop_created_called
|
57
|
+
|
58
|
+
hoards :login_date, :after_create => :login_date_created
|
59
|
+
hoards :other_prop, :after_create => :other_prop_created
|
60
|
+
|
61
|
+
def login_date_created
|
62
|
+
self.login_date_created_called = true
|
63
|
+
end
|
64
|
+
|
65
|
+
def other_prop_created
|
66
|
+
self.other_prop_created_called = true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
member = clazz.new
|
71
|
+
member.other_prop.create :value => DateTime.now
|
72
|
+
member.other_prop_created_called.should be_true
|
73
|
+
member.login_date_created_called.should be_false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'ignore_unchanged_value option' do
|
78
|
+
it 'should not add a value when ignore_unchanged_value is true and value is the same as the last value' do
|
79
|
+
clazz = Class.new(Plyushkin::Test::Member) do
|
80
|
+
hoards :login_date, :ignore_unchanged_values => true
|
81
|
+
end
|
82
|
+
|
83
|
+
member = clazz.new
|
84
|
+
now = DateTime.now
|
85
|
+
member.login_date.create(:value => now)
|
86
|
+
member.login_date.create(:value => now)
|
87
|
+
|
88
|
+
member.login_date.all.length.should == 1
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#validates' do
|
94
|
+
it 'should not be valid if hoarding property is not valid' do
|
95
|
+
clazz = Class.new(Plyushkin::Test::Member) do
|
96
|
+
hoards :geolocation, :type => Plyushkin::Test::CoordinateValue
|
97
|
+
end
|
98
|
+
clazz.stub(:model_name).and_return(ActiveModel::Name.new(clazz, nil, "test"))
|
99
|
+
|
100
|
+
member = clazz.new
|
101
|
+
member.geolocation.create(:x => 5)
|
102
|
+
member.should_not be_valid
|
103
|
+
member.errors.messages[:geolocation].count.should == 1
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe '#save' do
|
108
|
+
let(:clazz) do
|
109
|
+
clazz = Class.new(Plyushkin::Test::Member) do
|
110
|
+
hoards :login_date, :type => Plyushkin::Test::DateValue
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should load plyushkin persistence after find is called' do
|
115
|
+
member1 = clazz.new
|
116
|
+
now = DateTime.now
|
117
|
+
member1.login_date.create(:value => now)
|
118
|
+
member1.save!
|
119
|
+
|
120
|
+
member2 = clazz.find(member1.id)
|
121
|
+
member2.login_date.last.value.should === now
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should save hoarding property by id' do
|
125
|
+
member1 = clazz.new
|
126
|
+
now = DateTime.now
|
127
|
+
later = DateTime.now + 5
|
128
|
+
member1.login_date.create(:value => now)
|
129
|
+
member1.save!
|
130
|
+
|
131
|
+
member2 = clazz.new
|
132
|
+
member2.login_date.create(:value => later)
|
133
|
+
member2.save!
|
134
|
+
|
135
|
+
member1.reload.login_date.last.value.should === now
|
136
|
+
member2.reload.login_date.last.value.should === later
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#reload' do
|
141
|
+
let(:clazz) do
|
142
|
+
clazz = Class.new(Plyushkin::Test::Member) do
|
143
|
+
hoards :login_date, :type => Plyushkin::Test::DateValue
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should reload new data from persisted store' do
|
148
|
+
member = clazz.new
|
149
|
+
now = DateTime.now
|
150
|
+
member.login_date.create(:value => now)
|
151
|
+
member.save!
|
152
|
+
member.login_date.create(:value => now + 5)
|
153
|
+
|
154
|
+
member.reload
|
155
|
+
member.login_date.last.value.should === now
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Plyushkin::Persistence do
|
4
|
+
let(:service) do
|
5
|
+
service = Plyushkin::Service::Stub.new
|
6
|
+
service.put(1,
|
7
|
+
{ :name => [{ :value => "Steve" }] ,
|
8
|
+
:weight => [{ :value => 150 }],
|
9
|
+
:udt => [{ :x => 10, :y => 20 }]
|
10
|
+
}.to_json)
|
11
|
+
service
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:model) do
|
15
|
+
m = Plyushkin::Model.new(service)
|
16
|
+
m.register(:name, Plyushkin::StringValue)
|
17
|
+
m.register(:weight, Plyushkin::StringValue)
|
18
|
+
m.register(:udt, Plyushkin::Test::CoordinateValue)
|
19
|
+
m
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:persistence) do
|
23
|
+
p = Plyushkin::Persistence.new(model)
|
24
|
+
p.load(1)
|
25
|
+
p
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#properties' do
|
29
|
+
|
30
|
+
it 'should allow access to properties' do
|
31
|
+
persistence.properties.length.should == 3
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#save' do
|
36
|
+
it 'should save to source that load uses' do
|
37
|
+
persistence.properties[:name].create(:value => "Mike")
|
38
|
+
persistence.save(1)
|
39
|
+
persistence.load(1)
|
40
|
+
persistence.properties[:name].last.value.should == "Mike"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#load' do
|
45
|
+
it 'should parse json into an hash of properties' do
|
46
|
+
persistence.load(1)
|
47
|
+
property = persistence.properties[:name]
|
48
|
+
property.class.should == Plyushkin::Property
|
49
|
+
property.last.value.should == "Steve"
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should parse json for a user-defined type' do
|
53
|
+
persistence.load(1)
|
54
|
+
property = persistence.properties[:udt]
|
55
|
+
property.last.x.should == 10
|
56
|
+
property.last.y.should == 20
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should parse all history for a property' do
|
60
|
+
service.put(1,
|
61
|
+
{
|
62
|
+
:name => [
|
63
|
+
{ :value => "Ms. Julie Jones", :date => DateTime.now - 2.days },
|
64
|
+
{ :value => "Mrs. Julie Smith", :date => DateTime.now - 3.days }
|
65
|
+
]
|
66
|
+
}.to_json)
|
67
|
+
|
68
|
+
property = persistence.properties[:name]
|
69
|
+
property.all.length.should == 2
|
70
|
+
property.all[0].value.should == "Mrs. Julie Smith"
|
71
|
+
property.all[1].value.should == "Ms. Julie Jones"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should add an empty array for a property that isn't returned from service" do
|
75
|
+
model.register(:missing_property, Plyushkin::StringValue)
|
76
|
+
persistence.properties[:missing_property].all.should == []
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Plyushkin::Property do
|
4
|
+
describe '#create' do
|
5
|
+
it 'should add a StringValue' do
|
6
|
+
property = Plyushkin::Property.new(:property_name)
|
7
|
+
value = property.create(:value => 5)
|
8
|
+
value.class.should == Plyushkin::StringValue
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should pass the attributes to the simple value' do
|
12
|
+
property = Plyushkin::Property.new(:property_name)
|
13
|
+
date = DateTime.now - 3.days
|
14
|
+
value = property.create(:value => 5, :date => date)
|
15
|
+
value.value.should == 5
|
16
|
+
value.date.should == date
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should add a user-defined value' do
|
20
|
+
property = Plyushkin::Property.new(:property_name, :type => Plyushkin::Test::CoordinateValue)
|
21
|
+
value = property.create(:x => 5, :y => 10)
|
22
|
+
value.class.should == Plyushkin::Test::CoordinateValue
|
23
|
+
value.x.should == 5
|
24
|
+
value.y.should == 10
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'callbacks' do
|
28
|
+
it 'should call after_create callback after create' do
|
29
|
+
called = 0
|
30
|
+
callbacks = { :after_create => lambda{ called += 1 } }
|
31
|
+
property = Plyushkin::Property.new(:property_name, :callbacks => callbacks)
|
32
|
+
property.create(:value => 5)
|
33
|
+
called.should == 1
|
34
|
+
property.last.value.should == 5
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should not require an after_create callback' do
|
38
|
+
called = 0
|
39
|
+
callbacks = { :before_create => lambda{ called += 1 } }
|
40
|
+
property = Plyushkin::Property.new(:property_name, :callbacks => callbacks)
|
41
|
+
property.create(:value => 5)
|
42
|
+
called.should == 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'ignore_unchanged_value' do
|
47
|
+
it 'should not add a value when ignore_unchanged_value is true and value does not change' do
|
48
|
+
property = Plyushkin::Property.new(:property_name, :ignore_unchanged_values => true)
|
49
|
+
property.create(:value => 5)
|
50
|
+
property.create(:value => 5)
|
51
|
+
property.all.length.should == 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#all' do
|
57
|
+
it 'should return an array of all created values' do
|
58
|
+
property = Plyushkin::Property.new(:property_name)
|
59
|
+
value1 = property.create(:value => 5)
|
60
|
+
value2 = property.create(:value => 7)
|
61
|
+
property.all.should == [ value1, value2 ]
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should be sorted by value class date' do
|
65
|
+
property = Plyushkin::Property.new(:property_name)
|
66
|
+
value1 = property.create(:value => 5, :date => DateTime.now - 5.days)
|
67
|
+
value2 = property.create(:value => 7, :date => DateTime.now - 7.days)
|
68
|
+
property.all.should == [ value2, value1 ]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#last' do
|
73
|
+
it 'should return the most-recently added value' do
|
74
|
+
property = Plyushkin::Property.new(:property_name)
|
75
|
+
value1 = property.create(:value => 5)
|
76
|
+
value2 = property.create(:value => 7)
|
77
|
+
property.last.should == value2
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should return a new value if there are no values' do
|
81
|
+
property = Plyushkin::Property.new(:property_name)
|
82
|
+
property.last.should be_a(Plyushkin::NilValue)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#valid?' do
|
87
|
+
it 'should be valid if no values exist' do
|
88
|
+
property = Plyushkin::Property.new(:property_name)
|
89
|
+
property.should be_valid
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should be valid if last is valid and other values in array are not valid' do
|
93
|
+
property = Plyushkin::Property.new(:property_name, :type => Plyushkin::Test::PresenceTestValue)
|
94
|
+
value1 = property.create
|
95
|
+
value2 = property.create(:value => 5)
|
96
|
+
property.should be_valid
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should not be valid if last is not valid' do
|
100
|
+
property = Plyushkin::Property.new(:property_name, :type => Plyushkin::Test::PresenceTestValue)
|
101
|
+
value1 = property.create(:value => 5)
|
102
|
+
value2 = property.create
|
103
|
+
property.should_not be_valid
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should populate errors from values when not valid' do
|
107
|
+
property = Plyushkin::Property.new(:property_name, :type => Plyushkin::Test::PresenceTestValue)
|
108
|
+
property.create
|
109
|
+
property.valid?
|
110
|
+
property.errors.full_messages.should == [ "PropertyName: Value can't be blank" ]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#empty?' do
|
115
|
+
it 'should return true if no values were created' do
|
116
|
+
property = Plyushkin::Property.new(:property_name, :type => Plyushkin::Test::PresenceTestValue)
|
117
|
+
property.should be_empty
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should return false if values were not created' do
|
121
|
+
property = Plyushkin::Property.new(:property_name, :type => Plyushkin::Test::PresenceTestValue)
|
122
|
+
property.create
|
123
|
+
property.should_not be_empty
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it '#insert_position' do
|
128
|
+
property = Plyushkin::Property.new(:property_name)
|
129
|
+
value1 = property.create(:value => 7, :date => DateTime.now - 7.days)
|
130
|
+
value2 = property.create(:value => 5, :date => DateTime.now - 5.days)
|
131
|
+
property.insert_position(DateTime.now).should == 2
|
132
|
+
property.insert_position(DateTime.now - 6.days).should == 1
|
133
|
+
property.insert_position(DateTime.now - 8.days).should == 0
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Plyushkin::StringValue do
|
4
|
+
describe '#new' do
|
5
|
+
it 'should allow storing an integer' do
|
6
|
+
val = Plyushkin::StringValue.new(:value => 5)
|
7
|
+
val.value.should == 5
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should allow storing a string' do
|
11
|
+
val = Plyushkin::StringValue.new(:value => 'test')
|
12
|
+
val.value.should == 'test'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should use current if not specified' do
|
16
|
+
Timecop.freeze do
|
17
|
+
val = Plyushkin::StringValue.new(:value => 5)
|
18
|
+
val.date.should == DateTime.current
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should use provided date if specified' do
|
23
|
+
date = DateTime.new(2013, 12, 20)
|
24
|
+
val = Plyushkin::StringValue.new(:value => 5, :date => date)
|
25
|
+
val.date.should == date
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
|
8
|
+
path = File.dirname(File.expand_path(__FILE__))
|
9
|
+
require path + '/../lib/plyushkin'
|
10
|
+
require path + '/../lib/plyushkin/test'
|
11
|
+
Dir[path + "/support/**/*.rb"].each{ |f| require f }
|
12
|
+
|
13
|
+
require 'timecop'
|
14
|
+
require 'pry'
|
15
|
+
|
16
|
+
RSpec.configure do |config|
|
17
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
18
|
+
config.run_all_when_everything_filtered = true
|
19
|
+
config.filter_run :focus
|
20
|
+
|
21
|
+
# Run specs in random order to surface order dependencies. If you find an
|
22
|
+
# order dependency and want to debug it, you can fix the order by providing
|
23
|
+
# the seed, which is printed after each run.
|
24
|
+
# --seed 1234
|
25
|
+
config.order = 'random'
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Add sqlite
|
2
|
+
I18n.enforce_available_locales = false
|
3
|
+
ActiveRecord::Migration.verbose = false
|
4
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
5
|
+
class CreateMembers < ActiveRecord::Migration
|
6
|
+
def self.up
|
7
|
+
create_table :members do |t|
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
CreateMembers.up
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: plyushkin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Craig Israel
|
9
|
+
- Jeremy Hinkle
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2014-01-22 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.2.12
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: 3.2.12
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: bundler
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '1.3'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.3'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
description: Provides active record extension to capture historical property data
|
64
|
+
email:
|
65
|
+
- craig@theisraels.net
|
66
|
+
- jchinkle@gmail.com
|
67
|
+
executables: []
|
68
|
+
extensions: []
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- .gitignore
|
72
|
+
- .rspec
|
73
|
+
- Gemfile
|
74
|
+
- Gemfile.lock
|
75
|
+
- LICENSE.txt
|
76
|
+
- README.md
|
77
|
+
- Rakefile
|
78
|
+
- lib/plyushkin.rb
|
79
|
+
- lib/plyushkin/base_value.rb
|
80
|
+
- lib/plyushkin/core_ext/active_record_base.rb
|
81
|
+
- lib/plyushkin/core_ext/plyushkin_extensions.rb
|
82
|
+
- lib/plyushkin/model.rb
|
83
|
+
- lib/plyushkin/nil_value.rb
|
84
|
+
- lib/plyushkin/persistence.rb
|
85
|
+
- lib/plyushkin/property.rb
|
86
|
+
- lib/plyushkin/service.rb
|
87
|
+
- lib/plyushkin/service/stub.rb
|
88
|
+
- lib/plyushkin/string_value.rb
|
89
|
+
- lib/plyushkin/test.rb
|
90
|
+
- lib/plyushkin/test/value_types.rb
|
91
|
+
- lib/plyushkin/validators/presence.rb
|
92
|
+
- lib/plyushkin/version.rb
|
93
|
+
- plyushkin.gemspec
|
94
|
+
- spec/lib/base_value_spec.rb
|
95
|
+
- spec/lib/core_ext/active_record_base_spec.rb
|
96
|
+
- spec/lib/nil_value_spec.rb
|
97
|
+
- spec/lib/persistence_spec.rb
|
98
|
+
- spec/lib/property_spec.rb
|
99
|
+
- spec/lib/value_spec.rb
|
100
|
+
- spec/spec_helper.rb
|
101
|
+
- spec/support/sqlite.rb
|
102
|
+
homepage: http://github.com/OnlifeHealth/plyushkin
|
103
|
+
licenses:
|
104
|
+
- MIT
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 1.8.23
|
124
|
+
signing_key:
|
125
|
+
specification_version: 3
|
126
|
+
summary: Plyushkin - the attribute hoarder
|
127
|
+
test_files:
|
128
|
+
- spec/lib/base_value_spec.rb
|
129
|
+
- spec/lib/core_ext/active_record_base_spec.rb
|
130
|
+
- spec/lib/nil_value_spec.rb
|
131
|
+
- spec/lib/persistence_spec.rb
|
132
|
+
- spec/lib/property_spec.rb
|
133
|
+
- spec/lib/value_spec.rb
|
134
|
+
- spec/spec_helper.rb
|
135
|
+
- spec/support/sqlite.rb
|