plyushkin 0.0.2 → 0.0.3

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/Gemfile CHANGED
@@ -4,8 +4,9 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :test do
7
- gem 'rspec'
8
- gem 'timecop'
9
- gem 'pry-nav'
10
- gem 'sqlite3'
7
+ gem 'rspec', '~> 2.14.1'
8
+ gem 'timecop', '~> 0.7.1'
9
+ gem 'pry-nav', '~> 0.2.3'
10
+ gem 'sqlite3', '~> 1.3.8'
11
+ gem 'webmock', '~> 1.17.1'
11
12
  end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plyushkin (0.0.1)
4
+ plyushkin (0.0.3)
5
5
  activerecord (~> 3.2.12)
6
6
 
7
7
  GEM
@@ -18,9 +18,12 @@ GEM
18
18
  activesupport (3.2.16)
19
19
  i18n (~> 0.6, >= 0.6.4)
20
20
  multi_json (~> 1.0)
21
+ addressable (2.3.5)
21
22
  arel (3.0.3)
22
23
  builder (3.0.4)
23
24
  coderay (1.1.0)
25
+ crack (0.4.1)
26
+ safe_yaml (~> 0.9.0)
24
27
  diff-lcs (1.2.5)
25
28
  i18n (0.6.9)
26
29
  method_source (0.8.2)
@@ -40,10 +43,14 @@ GEM
40
43
  rspec-expectations (2.14.4)
41
44
  diff-lcs (>= 1.1.3, < 2.0)
42
45
  rspec-mocks (2.14.4)
46
+ safe_yaml (0.9.7)
43
47
  slop (3.4.7)
44
48
  sqlite3 (1.3.8)
45
49
  timecop (0.7.1)
46
50
  tzinfo (0.3.38)
51
+ webmock (1.17.1)
52
+ addressable (>= 2.2.7)
53
+ crack (>= 0.3.2)
47
54
 
48
55
  PLATFORMS
49
56
  ruby
@@ -51,8 +58,9 @@ PLATFORMS
51
58
  DEPENDENCIES
52
59
  bundler (~> 1.3)
53
60
  plyushkin!
54
- pry-nav
61
+ pry-nav (~> 0.2.3)
55
62
  rake
56
- rspec
57
- sqlite3
58
- timecop
63
+ rspec (~> 2.14.1)
64
+ sqlite3 (~> 1.3.8)
65
+ timecop (~> 0.7.1)
66
+ webmock (~> 1.17.1)
data/lib/plyushkin.rb CHANGED
@@ -9,6 +9,7 @@ require path + "/plyushkin/nil_value"
9
9
  require path + "/plyushkin/property"
10
10
  require path + "/plyushkin/model"
11
11
  require path + "/plyushkin/service"
12
+ require path + "/plyushkin/cache"
12
13
  require path + "/plyushkin/persistence"
13
14
  require path + "/plyushkin/validators/presence"
14
15
  require path + "/plyushkin/core_ext/plyushkin_extensions"
@@ -0,0 +1,14 @@
1
+ module Plyushkin::Cache
2
+ class << self
3
+ def cache
4
+ @cache ||= Plyushkin::Cache::Stub.new
5
+ end
6
+
7
+ def cache=(value)
8
+ @cache = value
9
+ end
10
+ end
11
+ end
12
+
13
+ require File.dirname(File.expand_path(__FILE__)) + "/cache/stub"
14
+ require File.dirname(File.expand_path(__FILE__)) + "/cache/rails_cache"
@@ -0,0 +1,9 @@
1
+ class Plyushkin::Cache::RailsCache
2
+ def read(key)
3
+ Rails.cache.read(key)
4
+ end
5
+
6
+ def write(key, value)
7
+ Rails.cache.write(key, value)
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ class Plyushkin::Cache::Stub
2
+ def initialize
3
+ @cache = {}
4
+ end
5
+
6
+ def write(key, value)
7
+ @cache[key] = value
8
+ end
9
+
10
+ def read(key)
11
+ @cache[key]
12
+ end
13
+
14
+ def clear
15
+ @cache = {}
16
+ end
17
+ end
@@ -12,9 +12,10 @@ ActiveRecord::Base.instance_eval do
12
12
  end
13
13
 
14
14
  def initialize_plyushkin
15
- class << self
15
+ class << self
16
16
  def plyushkin_model
17
- @plyushkin_model ||= Plyushkin::Model.new(Plyushkin::Service::Stub.new)
17
+ model_name = name ? name.parameterize : "record"
18
+ @plyushkin_model ||= Plyushkin::Model.new(Plyushkin::Service.service, model_name, Plyushkin::Cache.cache)
18
19
  end
19
20
  end
20
21
 
@@ -1,10 +1,13 @@
1
1
  class Plyushkin::Model
2
+ attr_reader :service, :name, :cache
2
3
 
3
- def initialize(service)
4
- @service = service
5
- @types = {}
4
+ def initialize(service, name, cache)
5
+ @service = service
6
+ @types = {}
6
7
  @ignore_unchanged_values = {}
7
- @callbacks = {}
8
+ @callbacks = {}
9
+ @name = name
10
+ @cache = cache
8
11
  end
9
12
 
10
13
  def register(name, type, opts={})
@@ -27,9 +30,4 @@ class Plyushkin::Model
27
30
  def ignore_unchanged_values
28
31
  @ignore_unchanged_values.dup
29
32
  end
30
-
31
- def service
32
- @service
33
- end
34
-
35
33
  end
@@ -14,17 +14,18 @@ class Plyushkin::Persistence
14
14
  (@properties || {}).each do |name, property|
15
15
  hash[name] = property.value_hashes
16
16
  end
17
- model.service.put(id, hash.to_json)
17
+ model.service.put(model.name, id, hash)
18
+ model.cache.write(get_key(model.name, id), hash)
18
19
  end
19
20
 
20
21
  def load(id)
21
22
  @properties = {}
22
- model.service.get(id).each do |name, values|
23
+ cached(id).each do |name, values|
23
24
  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] )
25
+ :callbacks => @callbacks[name.to_sym],
26
+ :ignore_unchanged_values => @model.ignore_unchanged_values[name.to_sym] )
26
27
  @properties[name.to_sym] = property
27
- end
28
+ end if id
28
29
  add_missing_properties
29
30
  end
30
31
 
@@ -32,17 +33,30 @@ class Plyushkin::Persistence
32
33
  @callbacks[name] = { callback => block }
33
34
  end
34
35
 
35
- private
36
+ private
36
37
  def model
37
38
  @model
38
39
  end
39
40
 
41
+ def cached(id)
42
+ data = model.cache.read(get_key(model.name, id))
43
+ unless data
44
+ data = model.service.get(model.name, id)
45
+ model.cache.write(get_key(model.name, id), data) if data
46
+ end
47
+ data
48
+ end
49
+
50
+ def get_key(name, id)
51
+ "plyushkin.#{name}.#{id}"
52
+ end
53
+
40
54
  def add_missing_properties
41
55
  (model.registered_types.keys - @properties.keys).each do |name|
42
56
  property = Plyushkin::Property.new(name,
43
- :type => model.registered_types[name],
44
- :callbacks => @callbacks[name],
45
- :ignore_unchanged_values => @model.ignore_unchanged_values[name])
57
+ :type => model.registered_types[name],
58
+ :callbacks => @callbacks[name],
59
+ :ignore_unchanged_values => @model.ignore_unchanged_values[name])
46
60
  @properties[name] = property
47
61
  end
48
62
  end
@@ -1,3 +1,9 @@
1
- module Plyushkin::Service; end
1
+ module Plyushkin::Service
2
+ class << self
3
+ attr_accessor :service
4
+ end
5
+ end
2
6
 
3
7
  require File.dirname(File.expand_path(__FILE__)) + "/service/stub"
8
+ require File.dirname(File.expand_path(__FILE__)) + "/service/web"
9
+
@@ -1,15 +1,24 @@
1
1
  class Plyushkin::Service::Stub
2
2
 
3
3
  def initialize
4
- @store = {}
4
+ @models = {}
5
5
  end
6
6
 
7
- def get(id)
8
- JSON.parse(@store[id] || "{}")
7
+ def get(model, id)
8
+ JSON.parse(get_store(model)[id] || "{}")
9
9
  end
10
10
 
11
- def put(id, json)
12
- @store[id] = json
11
+ def put(model, id, payload)
12
+ get_store(model)[id] = payload.to_json
13
+ end
14
+
15
+ private
16
+ def get_store(model)
17
+ if @models[model]
18
+ store = @models[model]
19
+ else
20
+ store = @models[model] = {}
21
+ end
13
22
  end
14
23
 
15
24
  end
@@ -0,0 +1,35 @@
1
+ require 'net/http'
2
+
3
+ class Plyushkin::Service::Web
4
+ attr_accessor :url
5
+
6
+ def initialize(opts={})
7
+ @url = opts.delete(:url)
8
+ end
9
+
10
+ def get(model, id)
11
+ uri = URI("#{url}/#{model}/#{id}")
12
+ use_ssl = true if uri.scheme == "https"
13
+
14
+ response = Net::HTTP.start(uri.host, uri.port,
15
+ :use_ssl => use_ssl) do |http|
16
+ request = Net::HTTP::Get.new(uri.to_s)
17
+ http.request(request)
18
+ end
19
+
20
+ JSON.parse(response.body)
21
+ end
22
+
23
+ def put(model, id, payload)
24
+ uri = URI("#{url}/#{model}/#{id}")
25
+ use_ssl = true if uri.scheme == "https"
26
+
27
+ response = Net::HTTP.start(uri.host, uri.port,
28
+ :use_ssl => use_ssl) do |http|
29
+ request = Net::HTTP::Put.new(uri.to_s)
30
+ request.body = payload.to_json
31
+ http.request(request)
32
+ end
33
+ end
34
+
35
+ end
@@ -10,6 +10,8 @@ module Plyushkin::Test
10
10
  end
11
11
 
12
12
  class Plyushkin::Test::Member < ActiveRecord::Base; end
13
+ class Plyushkin::Test::WidgetOne < ActiveRecord::Base; hoards :apples; end
14
+ class Plyushkin::Test::WidgetTwo < ActiveRecord::Base; hoards :beans; end
13
15
 
14
16
  class Plyushkin::Test::DateValue < Plyushkin::BaseValue
15
17
  persisted_attr :value, :formatter => :to_date
@@ -1,3 +1,3 @@
1
1
  module Plyushkin
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Plyushkin::Cache::Stub do
4
+ let (:cache) { Plyushkin::Cache::Stub.new }
5
+
6
+ describe "#write" do
7
+ it "should write values to the cache" do
8
+ cache.write("key", "value")
9
+ cache.read("key").should == "value"
10
+ end
11
+ end
12
+
13
+ end
@@ -33,6 +33,20 @@ describe ActiveRecord::Base do
33
33
  property = member.geolocation
34
34
  property.value_type.should == Plyushkin::Test::CoordinateValue
35
35
  end
36
+
37
+ it 'should use class name when setting up the service' do
38
+ widget_one = Plyushkin::Test::WidgetOne.new
39
+ widget_two = Plyushkin::Test::WidgetTwo.new
40
+
41
+ widget_one.apples.create(:value => 1)
42
+ widget_two.beans.create(:value => 2)
43
+
44
+ widget_one.save!
45
+ widget_two.save!
46
+
47
+ widget_one.reload.apples.last.value.should == 1
48
+ widget_two.reload.beans.last.value.should == 2
49
+ end
36
50
  end
37
51
 
38
52
  describe 'after_create option' do
@@ -155,6 +169,5 @@ describe ActiveRecord::Base do
155
169
  member.login_date.last.value.should === now
156
170
  end
157
171
  end
158
-
159
172
  end
160
173
  end
@@ -1,18 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Plyushkin::Persistence do
4
- let(:service) do
5
- service = Plyushkin::Service::Stub.new
6
- service.put(1,
4
+ let(:data) do
7
5
  { :name => [{ :value => "Steve" }] ,
8
6
  :weight => [{ :value => 150 }],
9
7
  :udt => [{ :x => 10, :y => 20 }]
10
- }.to_json)
8
+ }
9
+ end
10
+ let(:service) do
11
+ service = Plyushkin::Service.service
12
+ service.put("widget", 1, data)
11
13
  service
12
14
  end
13
15
 
16
+ let(:cache) { Plyushkin::Cache.cache }
17
+
14
18
  let(:model) do
15
- m = Plyushkin::Model.new(service)
19
+ m = Plyushkin::Model.new(service, "widget", cache)
16
20
  m.register(:name, Plyushkin::StringValue)
17
21
  m.register(:weight, Plyushkin::StringValue)
18
22
  m.register(:udt, Plyushkin::Test::CoordinateValue)
@@ -33,11 +37,10 @@ describe Plyushkin::Persistence do
33
37
  end
34
38
 
35
39
  describe '#save' do
36
- it 'should save to source that load uses' do
40
+ it 'should save to service' do
37
41
  persistence.properties[:name].create(:value => "Mike")
38
42
  persistence.save(1)
39
- persistence.load(1)
40
- persistence.properties[:name].last.value.should == "Mike"
43
+ service.get("widget", 1)["name"].last["value"].should == "Mike"
41
44
  end
42
45
  end
43
46
 
@@ -57,13 +60,13 @@ describe Plyushkin::Persistence do
57
60
  end
58
61
 
59
62
  it 'should parse all history for a property' do
60
- service.put(1,
63
+ service.put("widget", 1,
61
64
  {
62
65
  :name => [
63
66
  { :value => "Ms. Julie Jones", :date => DateTime.now - 2.days },
64
67
  { :value => "Mrs. Julie Smith", :date => DateTime.now - 3.days }
65
68
  ]
66
- }.to_json)
69
+ })
67
70
 
68
71
  property = persistence.properties[:name]
69
72
  property.all.length.should == 2
@@ -76,4 +79,21 @@ describe Plyushkin::Persistence do
76
79
  persistence.properties[:missing_property].all.should == []
77
80
  end
78
81
  end
82
+
83
+ describe "#caching" do
84
+ it "should use cache values on subsequent calls" do
85
+ persistence.properties[:weight].last.value.should == 150
86
+ service.put("widget", 1,
87
+ { :weight => [{ :value => 200 }] })
88
+ persistence.load(1)
89
+ persistence.properties[:weight].last.value.should == 150
90
+ end
91
+
92
+ it "should update the cache on save" do
93
+ persistence.properties[:name].create(:value => "Mike")
94
+ persistence.save(1)
95
+ persistence.load(1)
96
+ persistence.properties[:name].last.value.should == "Mike"
97
+ end
98
+ end
79
99
  end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Plyushkin::Service::Stub do
4
+ let (:service) { Plyushkin::Service::Stub.new }
5
+ let(:document) do
6
+ {
7
+ "weight" => [ {"value" => "5"} ]
8
+ }
9
+ end
10
+
11
+ describe "#get" do
12
+ it 'should get data' do
13
+ service.put("widget", 14, document)
14
+ service.get("widget", 14).should == document
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Plyushkin::Service::Web do
4
+ let(:document) do
5
+ {
6
+ "weight" => [ {"value" => "5"} ]
7
+ }
8
+ end
9
+
10
+ describe '#get' do
11
+ it 'should get json payload from service' do
12
+ stub_request(:get, 'http://plyushkin.com/widget/2').to_return(
13
+ :body => document.to_json)
14
+ service = Plyushkin::Service::Web.new(:url => "http://plyushkin.com")
15
+ service.get("widget", 2).should == document
16
+ end
17
+ end
18
+
19
+ describe '#put' do
20
+ it 'should send json payload' do
21
+ stub_request(:put, 'http://plyushkin.com/widget/2').
22
+ with(:body => document.to_json).
23
+ to_return(:status => 200)
24
+
25
+ service = Plyushkin::Service::Web.new(:url => "http://plyushkin.com")
26
+ service.put("widget", 2, document)
27
+ end
28
+ end
29
+ end
data/spec/spec_helper.rb CHANGED
@@ -5,13 +5,18 @@
5
5
  #
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
7
 
8
+ require 'pry'
8
9
  path = File.dirname(File.expand_path(__FILE__))
9
10
  require path + '/../lib/plyushkin'
11
+ Plyushkin::Service.service = Plyushkin::Service::Stub.new
12
+
10
13
  require path + '/../lib/plyushkin/test'
11
14
  Dir[path + "/support/**/*.rb"].each{ |f| require f }
12
15
 
13
16
  require 'timecop'
14
- require 'pry'
17
+ require 'webmock/rspec'
18
+
19
+ WebMock.disable_net_connect!(:allow_localhost => true)
15
20
 
16
21
  RSpec.configure do |config|
17
22
  config.treat_symbols_as_metadata_keys_with_true_values = true
@@ -23,5 +28,9 @@ RSpec.configure do |config|
23
28
  # the seed, which is printed after each run.
24
29
  # --seed 1234
25
30
  config.order = 'random'
31
+
32
+ config.after(:each) do
33
+ Plyushkin::Cache.cache.clear
34
+ end
26
35
  end
27
36
 
@@ -7,6 +7,12 @@ class CreateMembers < ActiveRecord::Migration
7
7
  create_table :members do |t|
8
8
  t.timestamps
9
9
  end
10
+ create_table :widget_ones do |t|
11
+ t.timestamps
12
+ end
13
+ create_table :widget_twos do |t|
14
+ t.timestamps
15
+ end
10
16
  end
11
17
  end
12
18
  CreateMembers.up
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plyushkin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-01-23 00:00:00.000000000 Z
13
+ date: 2014-01-31 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -77,6 +77,9 @@ files:
77
77
  - Rakefile
78
78
  - lib/plyushkin.rb
79
79
  - lib/plyushkin/base_value.rb
80
+ - lib/plyushkin/cache.rb
81
+ - lib/plyushkin/cache/rails_cache.rb
82
+ - lib/plyushkin/cache/stub.rb
80
83
  - lib/plyushkin/core_ext/active_record_base.rb
81
84
  - lib/plyushkin/core_ext/plyushkin_extensions.rb
82
85
  - lib/plyushkin/model.rb
@@ -85,6 +88,7 @@ files:
85
88
  - lib/plyushkin/property.rb
86
89
  - lib/plyushkin/service.rb
87
90
  - lib/plyushkin/service/stub.rb
91
+ - lib/plyushkin/service/web.rb
88
92
  - lib/plyushkin/string_value.rb
89
93
  - lib/plyushkin/test.rb
90
94
  - lib/plyushkin/test/value_types.rb
@@ -92,10 +96,13 @@ files:
92
96
  - lib/plyushkin/version.rb
93
97
  - plyushkin.gemspec
94
98
  - spec/lib/base_value_spec.rb
99
+ - spec/lib/cache/stub_spec.rb
95
100
  - spec/lib/core_ext/active_record_base_spec.rb
96
101
  - spec/lib/nil_value_spec.rb
97
102
  - spec/lib/persistence_spec.rb
98
103
  - spec/lib/property_spec.rb
104
+ - spec/lib/service/stub_spec.rb
105
+ - spec/lib/service/web_spec.rb
99
106
  - spec/lib/value_spec.rb
100
107
  - spec/spec_helper.rb
101
108
  - spec/support/sqlite.rb
@@ -126,10 +133,13 @@ specification_version: 3
126
133
  summary: Plyushkin - the attribute hoarder
127
134
  test_files:
128
135
  - spec/lib/base_value_spec.rb
136
+ - spec/lib/cache/stub_spec.rb
129
137
  - spec/lib/core_ext/active_record_base_spec.rb
130
138
  - spec/lib/nil_value_spec.rb
131
139
  - spec/lib/persistence_spec.rb
132
140
  - spec/lib/property_spec.rb
141
+ - spec/lib/service/stub_spec.rb
142
+ - spec/lib/service/web_spec.rb
133
143
  - spec/lib/value_spec.rb
134
144
  - spec/spec_helper.rb
135
145
  - spec/support/sqlite.rb