live_resource 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ live_resource
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-1.9.3-p392
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rspec'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Will Madden
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,76 @@
1
+ # LiveResource
2
+
3
+ A number of extremely good frameworks exist in Ruby for creating request/response applications, such as Rails,
4
+ Sinatra etc.
5
+
6
+ Requesting resources (for example, /profiles.json) is handled very well. In Rails the request would route through the
7
+ ProfilesController, load the collection of Profile models, and render the index view (MVC). Other framweorks supply
8
+ similar abstractions.
9
+
10
+ Unfortunately, frameworks based on the request/response model of interaction don't have an appropriate abstraction
11
+ for things that change between requests. For example, when a Profile is created the /profiles.json resource has
12
+ changed, but in the absence of a request there's no way for my application to notify clients that the resource has
13
+ changed.
14
+
15
+ The LiveResource gem adds the concept of a Resource, which is an object derived from server state (such as models) that
16
+ can be *pulled* (requested, as in the above example), or *pushed* when changes to server state are detected.
17
+
18
+ It also provides a Builder object that can be used to fluently describe the attributes of a live resource; namely:
19
+ its dependencies on elements of server state and the method of identifying individual instances of the resource.
20
+
21
+ ## Example
22
+
23
+ Describe the `profiles#show` resource.
24
+
25
+ ```ruby
26
+ profiles_show_resource = LiveResource::Builder.new(:profiles_show, ...)
27
+
28
+ # How do we identify individual profile_show_resources?
29
+ # This allows us to describe changes to a particular instance of the resource.
30
+ profiles_show_resource.identifier { |profile| "/profiles/#{profile.id}" }
31
+
32
+ # If a Profile changes, there will be a corresponding profiles_show_resource instance that changes.
33
+ # In other words, when a Profile changes, push an update to the profiles_show_resource identified by the calling the
34
+ # #identifier block we just defined and passing in the modified profile instance.
35
+ profiles_show_resource.depends_on(Profile) { |profile| push(profile) }
36
+ ```
37
+
38
+ ## Integrations
39
+
40
+ * [Rails](http://github.com/live-resource/rails)
41
+ * Allows you to define live resources inline in controllers
42
+ * Hooks into Rails' configuration
43
+ * [ActiveRecord](http://github.com/live-resource/rails)
44
+ * Adds support for specifying dependencies on ActiveRecord model classes
45
+ * [Pubnub](http://github.com/live-resource/pubnub)
46
+ * Adds support for pushing updates via Pubnub
47
+ * [RSpec](http://github.com/live-resource/rspec)
48
+ * Adds support for testing live resources in RSpec
49
+
50
+ ## Installation
51
+
52
+ Add this line to your application's Gemfile:
53
+
54
+ gem 'live_resource'
55
+
56
+ And then execute:
57
+
58
+ $ bundle
59
+
60
+ Or install it yourself as:
61
+
62
+ $ gem install live_resource
63
+
64
+ You will probably need one or more of the above integrations as well.
65
+
66
+ gem 'live_resource-rails' # For Rails projects
67
+ gem 'live_resource-activerecord' # If you're using AR
68
+ gem 'live_resource-pubnub' # To push updates through Pubnub
69
+
70
+ ## Contributing
71
+
72
+ 1. Fork it
73
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
74
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
75
+ 4. Push to the branch (`git push origin my-new-feature`)
76
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,44 @@
1
+ require "live_resource/resource"
2
+
3
+ module LiveResource
4
+ class Builder
5
+ attr_reader :resource
6
+
7
+ def initialize(resource_name, protocol, dependency_types, extensions = nil)
8
+ @dependency_types = dependency_types
9
+ @resource_class = Class.new(Resource) do # This creates an anonymous subclass of Resource
10
+ include extensions if extensions
11
+ end
12
+ @resource = @resource_class.new(resource_name, protocol)
13
+ end
14
+
15
+ def depends_on(target, *args, &block)
16
+ dependency_type = first_dependency_type_accepting(target)
17
+
18
+ unless dependency_type
19
+ raise <<-EOF
20
+ No dependency type is registered that accepts #{target.inspect}
21
+ Registered dependency types are: #{@dependency_types.inspect}
22
+ EOF
23
+ end
24
+
25
+ dependency = dependency_type.new(@resource, target, block, *args)
26
+ @resource.dependencies << dependency
27
+ end
28
+
29
+ def identifier(&block)
30
+ @identifier_proc = block
31
+
32
+ @resource_class.class_eval do
33
+ define_method(:identifier, &block)
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def first_dependency_type_accepting(target)
40
+ @dependency_types.each { |type| return type if type.accepts_target? target }
41
+ nil
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,21 @@
1
+ module LiveResource
2
+
3
+ class Dependency
4
+ attr_reader :target
5
+
6
+ def initialize(resource, target, proc)
7
+ @resource = resource
8
+ @proc = proc
9
+ @target = target
10
+ end
11
+
12
+ def invoke(*context)
13
+ @resource.instance_exec(*context, &@proc)
14
+ end
15
+
16
+ def watch
17
+ raise "Implement this method in a subclass, use it to set up hooks etc."
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,30 @@
1
+ module LiveResource
2
+ module Protocol
3
+
4
+ def publish_resource_reset(identifier)
5
+ publish_message(identifier, 'resource:reset')
6
+ end
7
+
8
+ def publish_property_change(identifier, property, value)
9
+ publish_message(identifier, 'resource:property:change', {
10
+ property: property,
11
+ value: value
12
+ })
13
+ end
14
+
15
+ def publish_collection_insert(identifier, property, element)
16
+ publish_message(identifier, 'resource:collection:insert', {
17
+ property: property,
18
+ element: element
19
+ })
20
+ end
21
+
22
+ def publish_collection_remove(identifier, property, element)
23
+ publish_message(identifier, 'resource:collection:remove', {
24
+ property: property,
25
+ element: element
26
+ })
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ module LiveResource
2
+ class Resource
3
+
4
+ attr_reader :name, :dependencies
5
+
6
+ def initialize(name, protocol)
7
+ @name = name
8
+ @protocol = protocol
9
+ @dependencies = []
10
+ end
11
+
12
+ def identifier(*context)
13
+ raise "You must define an identifier method for the resource '#{@name}'"
14
+ end
15
+
16
+ def push(*context)
17
+ @protocol.publish_resource_reset(identifier(*context))
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module LiveResource
2
+ module Test
3
+
4
+ class DependencyDouble < LiveResource::Dependency
5
+
6
+ def self.accepts_target?(anything)
7
+ true
8
+ end
9
+
10
+ def watch
11
+ @watching = true
12
+ end
13
+
14
+ def watching?
15
+ !!@watching
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ module LiveResource
2
+ module Test
3
+
4
+ class ProtocolDouble
5
+ include LiveResource::Protocol
6
+
7
+ attr_reader :messages
8
+
9
+ def initialize
10
+ @messages = []
11
+ end
12
+
13
+ private
14
+
15
+ def publish_message(resource_identifier, message_type, params = nil)
16
+ params ||= {}
17
+ message = params.merge({
18
+ :type => message_type,
19
+ ':resource_id' => resource_identifier
20
+ })
21
+ @messages << message
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ module LiveResource
2
+ VERSION = "0.0.1"
3
+ end
@@ -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 'live_resource/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "live_resource"
8
+ spec.version = LiveResource::VERSION
9
+ spec.authors = ["Will Madden"]
10
+ spec.email = ["will@letsgeddit.com"]
11
+ spec.description = %q{A DSL for describing resources that change in real time}
12
+ spec.summary = %q{A DSL for describing resources that change in real time}
13
+ spec.homepage = ""
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_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "live_resource-rspec"
25
+ end
@@ -0,0 +1,110 @@
1
+ require "spec_helper"
2
+
3
+ describe "building a LiveResource" do
4
+
5
+ let(:builder) do
6
+ LiveResource::Builder.new(resource_name, protocol, [LiveResource::Test::DependencyDouble])
7
+ end
8
+
9
+ let(:resource_name) { :user }
10
+
11
+ let(:resource) do
12
+ builder.resource
13
+ end
14
+
15
+ let(:protocol) { LiveResource::Test::ProtocolDouble.new }
16
+
17
+ describe 'the created resource' do
18
+
19
+ subject { resource }
20
+
21
+ describe '#name' do
22
+ subject { resource.name }
23
+
24
+ expect_it { to eq(resource_name) }
25
+ end
26
+
27
+ context 'when an identifier block is given' do
28
+ let(:identifier_block_invocations) { [] }
29
+ let(:identifier_block_return_value) { { a: 'b' } }
30
+ let(:identifier_block) do
31
+ # Preserve references to let'ed values inside Proc scope
32
+ _identifier_block_invocations = identifier_block_invocations
33
+ _identifier_block_return_value = identifier_block_return_value
34
+
35
+ Proc.new { |*args| _identifier_block_invocations << args; _identifier_block_return_value }
36
+ end
37
+
38
+ before do
39
+ builder.identifier(&identifier_block)
40
+ end
41
+
42
+ describe '#identifier' do
43
+ subject { resource.identifier *args }
44
+
45
+ let(:args) { [:a, 1, true, {}] }
46
+
47
+ it 'should invoke the supplied block' do
48
+ subject
49
+ expect(identifier_block_invocations.length).to be 1
50
+ expect(identifier_block_invocations.first).to eq args
51
+ end
52
+
53
+ expect_it { to be identifier_block_return_value }
54
+ end
55
+ end
56
+
57
+ context 'when a dependency is registered' do
58
+ before do
59
+ builder.depends_on(dependency_target, &dependency_block)
60
+ end
61
+
62
+ let(:dependency_target) { :some_component }
63
+
64
+ let(:dependency_block_invocations) { [] }
65
+ let(:dependency_block_return_value) { { a: 'b' } }
66
+ let(:dependency_block) do
67
+ # Preserve references to let'ed values inside Proc scope
68
+ _dependency_block_invocations = dependency_block_invocations
69
+ _dependency_block_return_value = dependency_block_return_value
70
+
71
+ Proc.new { |*args| _dependency_block_invocations << args; _dependency_block_return_value }
72
+ end
73
+
74
+ expect_it { to depend_on(dependency_target) }
75
+
76
+ context 'and the dependency is invoked' do
77
+ subject { dependency.invoke *context }
78
+
79
+ let(:dependency) { resource.dependencies.first }
80
+ let(:context) { [:a, 2, true] }
81
+
82
+ it 'should invoke the dependency block with the given context' do
83
+ subject
84
+ expect(dependency_block_invocations.length).to be 1
85
+ expect(dependency_block_invocations.first).to eq context
86
+ end
87
+
88
+ describe 'the block' do
89
+ let(:dependency_block) do
90
+ ->(a,b,c) { push('hello', 'world!') }
91
+ end
92
+
93
+ let(:identifier_block) do
94
+ ->(a, b) { [a, b].join(', ') }
95
+ end
96
+
97
+ before do
98
+ builder.identifier(&identifier_block)
99
+ end
100
+
101
+ it 'should be able to publish a resource reset' do
102
+ subject
103
+ expect(protocol.messages).to include({ :type => 'resource:reset', ':resource_id' => 'hello, world!' })
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ end
@@ -0,0 +1,132 @@
1
+ require "spec_helper"
2
+
3
+ describe LiveResource::Builder do
4
+
5
+ let(:builder) { LiveResource::Builder.new(resource_name, protocol, dependency_types, extension_module) }
6
+ let(:resource_name) { [:some, :thing] }
7
+ let(:protocol) { double(LiveResource::Protocol) }
8
+ let(:dependency_types) {}
9
+ let(:extension_module) {}
10
+
11
+ describe "#initialize" do
12
+ subject { builder }
13
+
14
+ let(:resource_class) { double(Class, :new => resource) }
15
+ let(:resource) { double(LiveResource::Resource) }
16
+
17
+ describe 'creating the new Resource' do
18
+ before do
19
+ Class.stub(:new).and_return(resource_class)
20
+ LiveResource::Resource.stub(:new).and_return(resource)
21
+ end
22
+
23
+ it "should create a new Resource class" do
24
+ Class.should_receive(:new).with(LiveResource::Resource)
25
+ subject
26
+ end
27
+
28
+ it "should initialize a new instance of the Resource subclass" do
29
+ resource_class.should_receive(:new).with(resource_name, protocol)
30
+ subject
31
+ end
32
+ end
33
+
34
+ context 'when an extension module is supplied' do
35
+ let(:resource_class) do
36
+ class DummyClass
37
+ def initialize(*args)
38
+ end
39
+ end
40
+ DummyClass
41
+ end
42
+
43
+ let(:extension_module) do
44
+ module ExtensionModule
45
+ def some_extension_method
46
+ end
47
+ end
48
+ ExtensionModule
49
+ end
50
+
51
+ it 'should mix it into the new subclass' do
52
+ subject
53
+ expect(builder.resource).to respond_to(:some_extension_method)
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#depends_on" do
59
+ subject { builder.depends_on(target, &block) }
60
+
61
+ let(:target) { :some_component }
62
+ let(:block) { Proc.new {} }
63
+ let(:dependency_types) { [dependency_type_1, dependency_type_2, dependency_type_3] }
64
+
65
+ let(:dependency_type_1) { double('Dependency Type 1', accepts_target?: false) }
66
+ let(:dependency_type_2) { double('Dependency Type 2', accepts_target?: true, new: nil) }
67
+ let(:dependency_type_3) { double('Dependency Type 3', accepts_target?: false) }
68
+
69
+ it 'should test each dependency type up to the first one which accepts the target' do
70
+ dependency_type_1.should_receive(:accepts_target?).with(target)
71
+ dependency_type_2.should_receive(:accepts_target?).with(target)
72
+ dependency_type_3.should_not_receive(:accepts_target?)
73
+ subject
74
+ end
75
+
76
+ context 'when no dependency types accept the target' do
77
+ before do
78
+ dependency_type_2.stub(accepts_target?: false)
79
+ end
80
+
81
+ it 'should raise an error' do
82
+ expect(-> { subject }).to raise_error(/no dependency/i)
83
+ end
84
+ end
85
+
86
+ context 'when one of the dependency types accepts the target' do
87
+ let(:resource) { double(LiveResource::Resource, dependencies: []) }
88
+ let(:dependency) { double(LiveResource::Dependency) }
89
+
90
+ before do
91
+ resource_subclass = double(Class, new: resource)
92
+ Class.stub(new: resource_subclass)
93
+ dependency_type_2.stub(new: dependency)
94
+ end
95
+
96
+ context 'and no extra arguments are given' do
97
+ it 'should instantiate the dependency type that accepts the target' do
98
+ dependency_type_2.should_receive(:new).with(resource, target, block)
99
+ subject
100
+ end
101
+ end
102
+
103
+ context 'and some extra arguments are given' do
104
+ subject { builder.depends_on(target, *args, &block) }
105
+
106
+ let(:args) { [:a, 2, true] }
107
+
108
+ it 'should instantiate the dependency type that accepts the target with the extra arguments' do
109
+ dependency_type_2.should_receive(:new).with(resource, target, block, *args)
110
+ subject
111
+ end
112
+ end
113
+
114
+ it "should add the result to the Resource's dependencies collection" do
115
+ subject
116
+ expect(resource.dependencies).to include(dependency)
117
+ end
118
+ end
119
+ end
120
+
121
+ describe "#identifier" do
122
+ subject { builder.identifier(&block) }
123
+
124
+ let(:block) { Proc.new { |a, b| [a, b] } }
125
+
126
+ it "should define a new identifier method on the resource subclass" do
127
+ subject
128
+ expect(builder.resource.identifier(1, 2)).to eq([1, 2])
129
+ end
130
+ end
131
+
132
+ end
@@ -0,0 +1,51 @@
1
+ require "spec_helper"
2
+
3
+ describe LiveResource::Dependency do
4
+ let(:dependency) { LiveResource::Dependency.new(resource, target, proc) }
5
+
6
+ let(:resource) { double(LiveResource::Resource) }
7
+ let(:target) { :some_component }
8
+ let(:proc) {}
9
+
10
+ describe "watch" do
11
+
12
+ subject { dependency.watch }
13
+
14
+ it "should raise an error" do
15
+ expect(-> { subject }).to raise_error
16
+ end
17
+
18
+ end
19
+
20
+ describe "invoke" do
21
+ subject { dependency.invoke(*context) }
22
+
23
+ let(:context) { [double(), double()] }
24
+ let(:resource) { double(LiveResource::Resource, name: "blah") }
25
+
26
+ let(:proc_invocations) { [] }
27
+ let(:proc_return_value) { { a: 'b' } }
28
+ let(:proc) do
29
+ # Preserve references to let'ed values inside Proc scope
30
+ _proc_invocations = proc_invocations
31
+ _proc_return_value = proc_return_value
32
+
33
+ Proc.new do |*args|
34
+ _proc_invocations << { :self => self, :args => args }
35
+ _proc_return_value
36
+ end
37
+ end
38
+
39
+ it "should execute the proc in the context of the resource" do
40
+ subject
41
+ expect(proc_invocations.length).to be 1
42
+ expect(proc_invocations.first[:self]).to be resource
43
+ end
44
+
45
+ it "should pass the context to the proc" do
46
+ subject
47
+ expect(proc_invocations.length).to be 1
48
+ expect(proc_invocations.first[:args]).to eq context
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,50 @@
1
+ require "spec_helper"
2
+ require "live_resource/resource"
3
+
4
+ describe LiveResource::Resource do
5
+
6
+ let(:resource) { LiveResource::Resource.new(resource_name, protocol) }
7
+ let(:resource_name) { "some_resource" }
8
+ let(:protocol) { double(LiveResource::Protocol) }
9
+
10
+ describe "#intialize" do
11
+ subject { resource }
12
+
13
+ its(:name) { should be resource_name }
14
+
15
+ it 'should retain its protocol' do
16
+ expect(subject.instance_variable_get(:@protocol)).to be(protocol)
17
+ end
18
+ end
19
+
20
+ describe "#identifier" do
21
+ subject { resource.identifier(:a, :b) }
22
+
23
+ it "should raise an exception" do
24
+ expect(lambda { subject }).to raise_exception
25
+ end
26
+ end
27
+
28
+ describe "#push" do
29
+ subject { resource.push(*context) }
30
+
31
+ let(:identifier) { 'a/b/c' }
32
+ let(:context) { [:a, :b, :c] }
33
+
34
+ before do
35
+ resource.stub(identifier: identifier)
36
+ protocol.stub(publish_resource_reset: nil)
37
+ end
38
+
39
+ it 'should generate the identifier' do
40
+ resource.should_receive(:identifier).with(*context)
41
+ subject
42
+ end
43
+
44
+ it 'should publish a resource reset' do
45
+ protocol.should_receive(:publish_resource_reset).with(identifier)
46
+ subject
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,34 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ def require_tree(path)
4
+ path = File.expand_path(path, File.dirname(__FILE__))
5
+
6
+ files = Dir.glob(File.join(path, '**/*.rb'))
7
+ raise "Directory '#{path}' is empty" unless files.length > 0
8
+
9
+ files.each { |file| puts " require #{file}"; require file }
10
+ end
11
+
12
+ require_tree '../lib'
13
+ require_tree 'support'
14
+ require 'live_resource/rspec'
15
+
16
+ module DescribeHelpers
17
+ def expect_its(*args, &block)
18
+ its(*args, &block)
19
+ end
20
+ end
21
+
22
+ RSpec.configure do |config|
23
+ config.include LiveResource::RSpec
24
+
25
+ # Alias the existing one-liner syntax to #expect_it, so that lines like the following will work:
26
+ # expect_it { to be(:something) }
27
+ config.alias_example_to :expect_it
28
+ config.extend(DescribeHelpers)
29
+ end
30
+
31
+ RSpec::Core::ExampleGroup.module_eval do
32
+ alias to should
33
+ alias to_not should_not
34
+ end
@@ -0,0 +1,38 @@
1
+ module LiveResourceMatchers
2
+ # Tests that a LiveResource::Resource has a dependency on the given target, optionally for the given events.
3
+ class DependOn
4
+ def initialize(target)
5
+ @target = target
6
+ end
7
+
8
+ def matches?(live_resource)
9
+ @live_resource = live_resource
10
+
11
+ @actual_targets = @live_resource.dependencies.map { |dependency| dependency.target }
12
+
13
+ return @actual_targets.include?(@target)
14
+ end
15
+
16
+ def failure_message
17
+ "expected '#{@live_resource.name}' resource to depend on #{@target.inspect} but it instead depended on #{@actual_targets}"
18
+ end
19
+
20
+ def negative_failure_message
21
+ "expected '#{@live_resource.name}' resource not to depend on #{@target.inspect} but it instead depended on #{@actual_targets}"
22
+ end
23
+
24
+ def description
25
+ "depend on #{@target.inspect}"
26
+ end
27
+
28
+ def for_events(*events)
29
+ @for_events = events
30
+ self
31
+ end
32
+ end
33
+
34
+ def depend_on(expected)
35
+ DependOn.new(expected)
36
+ end
37
+
38
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: live_resource
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Will Madden
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: live_resource-rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: A DSL for describing resources that change in real time
79
+ email:
80
+ - will@letsgeddit.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - .rspec
87
+ - .ruby-gemset
88
+ - .ruby-version
89
+ - .travis.yml
90
+ - Gemfile
91
+ - LICENSE.txt
92
+ - README.md
93
+ - Rakefile
94
+ - lib/live_resource/builder.rb
95
+ - lib/live_resource/dependency.rb
96
+ - lib/live_resource/protocol.rb
97
+ - lib/live_resource/resource.rb
98
+ - lib/live_resource/test/dependency_double.rb
99
+ - lib/live_resource/test/protocol_double.rb
100
+ - lib/live_resource/version.rb
101
+ - live_resource.gemspec
102
+ - spec/integration/integration_spec.rb
103
+ - spec/live_resource/builder_spec.rb
104
+ - spec/live_resource/dependency_spec.rb
105
+ - spec/live_resource/resource_spec.rb
106
+ - spec/spec_helper.rb
107
+ - spec/support/live_resource_matchers.rb
108
+ homepage: ''
109
+ licenses:
110
+ - MIT
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubyforge_project:
129
+ rubygems_version: 1.8.25
130
+ signing_key:
131
+ specification_version: 3
132
+ summary: A DSL for describing resources that change in real time
133
+ test_files:
134
+ - spec/integration/integration_spec.rb
135
+ - spec/live_resource/builder_spec.rb
136
+ - spec/live_resource/dependency_spec.rb
137
+ - spec/live_resource/resource_spec.rb
138
+ - spec/spec_helper.rb
139
+ - spec/support/live_resource_matchers.rb