live_resource 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 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