cloud_powers 0.2.7.23 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.test.env.example +6 -6
- data/.travis.yml +1 -1
- data/README +190 -0
- data/cloud_powers.gemspec +4 -4
- data/lib/cloud_powers.rb +3 -13
- data/lib/cloud_powers/aws_resources.rb +21 -4
- data/lib/cloud_powers/creatable.rb +122 -0
- data/lib/cloud_powers/helpers.rb +58 -0
- data/lib/cloud_powers/helpers/lang_help.rb +288 -0
- data/lib/cloud_powers/helpers/logic_help.rb +152 -0
- data/lib/cloud_powers/helpers/path_help.rb +90 -0
- data/lib/cloud_powers/node.rb +69 -68
- data/lib/cloud_powers/node/instance.rb +52 -0
- data/lib/cloud_powers/resource.rb +44 -0
- data/lib/cloud_powers/storage.rb +27 -14
- data/lib/{stubs → cloud_powers/stubs}/aws_stubs.rb +37 -14
- data/lib/cloud_powers/synapse/broadcast.rb +117 -0
- data/lib/cloud_powers/synapse/broadcast/channel.rb +44 -0
- data/lib/cloud_powers/synapse/pipe.rb +211 -0
- data/lib/cloud_powers/synapse/pipe/stream.rb +41 -0
- data/lib/cloud_powers/synapse/queue.rb +357 -0
- data/lib/cloud_powers/synapse/queue/board.rb +61 -95
- data/lib/cloud_powers/synapse/queue/poller.rb +29 -0
- data/lib/cloud_powers/synapse/synapse.rb +10 -12
- data/lib/cloud_powers/synapse/web_soc.rb +13 -0
- data/lib/cloud_powers/synapse/web_soc/soc_client.rb +52 -0
- data/lib/cloud_powers/synapse/web_soc/soc_server.rb +48 -0
- data/lib/cloud_powers/version.rb +1 -1
- data/lib/cloud_powers/zenv.rb +13 -12
- metadata +24 -13
- data/lib/cloud_powers/context.rb +0 -275
- data/lib/cloud_powers/delegator.rb +0 -113
- data/lib/cloud_powers/helper.rb +0 -453
- data/lib/cloud_powers/synapse/websocket/websocclient.rb +0 -53
- data/lib/cloud_powers/synapse/websocket/websocserver.rb +0 -46
- data/lib/cloud_powers/workflow_factory.rb +0 -160
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 403667ef1b83f93c4534a4273849b4cd471385e4
|
4
|
+
data.tar.gz: c233cc41bd999aaa9b0bc6cc58d1a08c1947af73
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bcad8e1544017abf5b498b546271cadb8071d1c498fd599983e9d4e5d7ed391d3033e82589ddd0aec49a171cb098804dfad9d0439d19cb5fb7f10a23d80d3828
|
7
|
+
data.tar.gz: a95f21bad47ff61cf1175716dff63322dc20908b25d92201a59fb61d785f86121e9589b5c4ee939fa0fef02a64ad633fd247c8a0a490f7f2ba26732d27010bab
|
data/.gitignore
CHANGED
data/.test.env.example
CHANGED
@@ -2,21 +2,21 @@
|
|
2
2
|
PROJECT_ROOT=""
|
3
3
|
|
4
4
|
# Aws access:
|
5
|
-
AWS_ACCESS_KEY_ID=""
|
6
|
-
AWS_SECRET_ACCESS_KEY=""
|
7
|
-
ACCOUNT_NUMBER=""
|
5
|
+
AWS_ACCESS_KEY_ID="AAAAAAAAAAAAAAAAAAAA"
|
6
|
+
AWS_SECRET_ACCESS_KEY="xxddccffvvggbbhhnnjjmmkknhhd+2344322341"
|
7
|
+
ACCOUNT_NUMBER="0112233445566"
|
8
8
|
|
9
|
-
# Aws areas and auth-related locations:
|
9
|
+
# Aws areas and auth-related locations:
|
10
10
|
AWS_REGION=""
|
11
11
|
|
12
12
|
# Aws Build info:
|
13
|
-
|
13
|
+
NODE_IMAGE="for Cerebrums to create a node"
|
14
14
|
|
15
15
|
# Aws kinesis stream names
|
16
16
|
STATUS_STREAM="e.g. kinesis stream name"
|
17
17
|
|
18
18
|
# Aws s3 buckets etc
|
19
|
-
|
19
|
+
JOB_STORAGE="e.g. s3 object name"
|
20
20
|
|
21
21
|
# Aws sqs queue addresses
|
22
22
|
BACKLOG_QUEUE_ADDRESS=""
|
data/.travis.yml
CHANGED
data/README
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/cloud_powers.svg)](https://badge.fury.io/rb/cloud_powers)CloudPowers
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
CloudPowers is a wrapper around AWS and in the future, other cloud service Providers.
|
6
|
+
It was developed specifically for the Brain project but hopefully can be used
|
7
|
+
in any other ruby project that needs to use cloud service providers' resources.
|
8
|
+
|
9
|
+
Version 0.2.8 has a some EC2, S3, SQS, SNS, Kinesis, websockets and a few other
|
10
|
+
features you can find in the docs. There is also limitted support for stubbing
|
11
|
+
AWS RESTful API calls. That can come in handy for local testing and extra setup on
|
12
|
+
AWS resource clients.
|
13
|
+
|
14
|
+
The next versions will have more Kinesis, Workflow integration and IoT.
|
15
|
+
|
16
|
+
This project is actively being developed, so more additions, specs and docs
|
17
|
+
will be added and updated frequently with new funcionality but the gem will
|
18
|
+
follow good practices for versioning. Input is always welcome.
|
19
|
+
Enjoy!
|
20
|
+
|
21
|
+
* Each module in Cloud Powers is in charge of a specific type of task that helps bring projects together and communicate with the outside world.
|
22
|
+
|
23
|
+
Below is a breakdown of the installation, common services provided and an example or 2 of popular methods.
|
24
|
+
_Better docs are on the way_
|
25
|
+
|
26
|
+
## Installation
|
27
|
+
|
28
|
+
Add this line to your application's Gemfile:
|
29
|
+
|
30
|
+
```Ruby
|
31
|
+
gem 'cloud_powers'
|
32
|
+
```
|
33
|
+
|
34
|
+
then execute:
|
35
|
+
|
36
|
+
$ bundle
|
37
|
+
|
38
|
+
Or install it yourself as:
|
39
|
+
|
40
|
+
$ gem install cloud_powers
|
41
|
+
|
42
|
+
then either:
|
43
|
+
* set environment variables that matches the below group
|
44
|
+
* fill out a .env file and load it from the class that is using CloudPowers, like this
|
45
|
+
Notes:
|
46
|
+
* The code does its best in many cases to make a good guess at some of the configuration
|
47
|
+
for you but if you set them in your system environment variables or in the .env file,
|
48
|
+
it'll have a much better
|
49
|
+
```Ruby
|
50
|
+
require 'dotenv'
|
51
|
+
Dotenv.load('path to your .env file')
|
52
|
+
```
|
53
|
+
_things you need for pre-v1_:
|
54
|
+
```Ruby
|
55
|
+
# Aws access:
|
56
|
+
AWS_ACCESS_KEY_ID=""
|
57
|
+
AWS_SECRET_ACCESS_KEY=""
|
58
|
+
|
59
|
+
# Aws areas and auth-related locations:
|
60
|
+
AWS_REGION=""
|
61
|
+
|
62
|
+
# Aws Build info:
|
63
|
+
AMI_NAME="for Cerebrums to create a node"
|
64
|
+
|
65
|
+
# Aws kinesis stream names
|
66
|
+
STATUS_STREAM="e.g. kinesis stream name"
|
67
|
+
|
68
|
+
# Aws s3 buckets etc
|
69
|
+
TASK_STORAGE="e.g. s3 object name"
|
70
|
+
|
71
|
+
# Aws sqs queue addresses
|
72
|
+
BACKLOG_QUEUE_ADDRESS=""
|
73
|
+
WIP_QUEUE_ADDRESS=""
|
74
|
+
FINISHED_QUEUE_ADDRESS=""
|
75
|
+
```
|
76
|
+
|
77
|
+
## Usage
|
78
|
+
|
79
|
+
### AwsResource
|
80
|
+
* AWS resources that should be used by many services, e.g. Delegator _on EC2_ uses S3, EC2 and SQS to gain knowledge about the
|
81
|
+
context it will be working in.
|
82
|
+
|
83
|
+
|
84
|
+
### Delegator
|
85
|
+
* Helps a node figure out what task it should be running, where its executables are, gathers it/them and loads them.
|
86
|
+
* Lives in the Job and Task instantiation chain
|
87
|
+
|
88
|
+
|
89
|
+
### Helper
|
90
|
+
* useful shared methods, like one that turns a string into snake_case
|
91
|
+
|
92
|
+
|
93
|
+
### SelfAwareness
|
94
|
+
* gets and sets info about the instance -> Neuron/Cerebrum/etc)
|
95
|
+
```Ruby
|
96
|
+
get_awareness!
|
97
|
+
```
|
98
|
+
* retrieves and sets all metadata from the EC2 instance and a few other things like the instance hostname (can find the instance IP from here).
|
99
|
+
* See EC2 metadata for details on the instance/node metadata that is set.
|
100
|
+
* Additionally, the instance public hostname, id and a few others are set using other-than-EC2-metadata methods.
|
101
|
+
|
102
|
+
|
103
|
+
### SmashError
|
104
|
+
|
105
|
+
|
106
|
+
### Storage
|
107
|
+
* S3
|
108
|
+
|
109
|
+
|
110
|
+
### Synapse
|
111
|
+
* A Synapse is used for communicating, usually between nodes and an external source for status updates but the Synapse can handle any kind of information that needs to be passed.
|
112
|
+
* Architecture
|
113
|
+
* The Synapse is a communications module that is broken up into separate types of communication, for separate needs.
|
114
|
+
* There are 2 modules, soon to be 3, inside the Synapse module:
|
115
|
+
|
116
|
+
#### Queue
|
117
|
+
* like a task list or a message board for asynchronous communication
|
118
|
+
* Board <Struct>:
|
119
|
+
* interface with Queue config, data, name, etc.
|
120
|
+
```Ruby
|
121
|
+
default_workflow = Workflow.new
|
122
|
+
board = Board.new(default_workflow)
|
123
|
+
board.name
|
124
|
+
=> 'backlog'
|
125
|
+
board.address
|
126
|
+
=> 'http://aws-url/backlog-board-url'
|
127
|
+
board.next_board # useful because this is a simple state-machine implementation
|
128
|
+
=> 'wip'
|
129
|
+
```
|
130
|
+
Example usage:
|
131
|
+
1. Give the entire stream name or a symbol or string that is found in the .env for the name of the Queue
|
132
|
+
2. provide a block that will create the record that gets sent to the board
|
133
|
+
```Ruby
|
134
|
+
poll(board_name <string|symbol>, opts <optional config Hash>) { block }
|
135
|
+
```
|
136
|
+
or
|
137
|
+
```Ruby
|
138
|
+
poll(:backlog) { |msg, stats| Task.new(instance_id, msg) if stats.success? }
|
139
|
+
```
|
140
|
+
or
|
141
|
+
```Ruby
|
142
|
+
poll(:backlog, wait_time: 30, delete: false) do
|
143
|
+
edited_message = sitrep.merge(foo: 'bar')
|
144
|
+
update = some_method(edited_message)
|
145
|
+
end
|
146
|
+
```
|
147
|
+
#### Pipe
|
148
|
+
* Good for real time information passing, like status updates, results reporting, operations, etc.
|
149
|
+
* The Pipe module is for communicating via streams. Piping is meant to be a way to communicate status, problems and other general info or huge result sets and things of that nature. There can be very high traffic through the pipe or none at all. Very soon (probably V-0.2.6 or 7), Cerebrums will be data consumers, to the Java KCL and MultiLangDaemon level, so keeping messages straight is done via partition ID. The partition ID of any message is to identify which node the message is about or the "batch" or "group" or any other concept like that. So the instance ID is used in nodes like the Neuron and Cerebrum and other identifiers that are deemed best are used in other projects as a batch ID.
|
150
|
+
|
151
|
+
Example usage:
|
152
|
+
```Ruby
|
153
|
+
pipe_to(stream_name <string/symbol>) { &block }
|
154
|
+
```
|
155
|
+
```Ruby
|
156
|
+
pipe_to(:status_queue) { sitrep(content: 'workflowComplete') }
|
157
|
+
```
|
158
|
+
and for multiple records (KCL)
|
159
|
+
```Ruby
|
160
|
+
flow_to(stream_name <string/symbol>) { &block }
|
161
|
+
```
|
162
|
+
```Ruby
|
163
|
+
flow_to(:status_queue) do
|
164
|
+
interesting_instances = neurons.map do |neuron|
|
165
|
+
return neuron if neuron.workflow.done?
|
166
|
+
end
|
167
|
+
find_efficient_neurons(interesting_instances) # this gets sent through the Pipe
|
168
|
+
end
|
169
|
+
```
|
170
|
+
|
171
|
+
|
172
|
+
#### Memory
|
173
|
+
* Allows the nodes to have a collective awareness of each other, the environment they work in and other Jobs (Coming soon...)
|
174
|
+
|
175
|
+
|
176
|
+
## Development
|
177
|
+
|
178
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
179
|
+
|
180
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
181
|
+
|
182
|
+
## Contributing
|
183
|
+
|
184
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/adam-phillipps/cloud_powers.
|
185
|
+
|
186
|
+
|
187
|
+
## License
|
188
|
+
|
189
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
190
|
+
|
data/cloud_powers.gemspec
CHANGED
@@ -15,16 +15,16 @@ Gem::Specification.new do |spec|
|
|
15
15
|
It was developed specifically for the Brain project but hopefully can be used
|
16
16
|
in any other ruby project that needs to use cloud service providers' resources.
|
17
17
|
|
18
|
-
Version 0
|
18
|
+
Version 1.0 has a some EC2, S3, SQS, SNS, Kinesis, websockets and a few other
|
19
19
|
features you can find in the docs. There is also limitted support for stubbing
|
20
20
|
AWS RESTful API calls. That can come in handy for local testing and extra setup on
|
21
21
|
AWS resource clients.
|
22
22
|
|
23
|
-
The next versions will have more Kinesis, Workflow integration and IoT.
|
24
|
-
|
25
23
|
This project is actively being developed, so more additions, specs and docs
|
26
24
|
will be added and updated frequently with new funcionality but the gem will
|
27
|
-
follow good practices for versioning
|
25
|
+
follow good practices for versioning and so the behavior won't change on
|
26
|
+
existing features.
|
27
|
+
Input is always welcome. :thumbsup:
|
28
28
|
Enjoy!
|
29
29
|
EOF
|
30
30
|
spec.homepage = 'https://github.com/adam-phillipps/cloud_powers'
|
data/lib/cloud_powers.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
require 'cloud_powers/auth'
|
2
2
|
require 'cloud_powers/aws_resources'
|
3
|
-
require 'cloud_powers/
|
4
|
-
require 'cloud_powers/delegator'
|
5
|
-
require 'cloud_powers/helper'
|
3
|
+
require 'cloud_powers/helpers'
|
6
4
|
require 'cloud_powers/node'
|
7
|
-
require 'cloud_powers/
|
5
|
+
require 'cloud_powers/resource'
|
8
6
|
require 'cloud_powers/storage'
|
9
7
|
require 'cloud_powers/version'
|
10
|
-
require 'cloud_powers/
|
8
|
+
require 'cloud_powers/synapse/synapse'
|
11
9
|
|
12
10
|
# The Smash module allows us to use CloudPowers under a shared name space with other projects.
|
13
11
|
module Smash
|
@@ -15,21 +13,13 @@ module Smash
|
|
15
13
|
module CloudPowers
|
16
14
|
# Authentication mixin
|
17
15
|
extend Smash::CloudPowers::Auth
|
18
|
-
# Dynamic Resource creation and delegation
|
19
|
-
extend Smash::CloudPowers::Delegator
|
20
16
|
# Aws clients, like EC2 and S3
|
21
17
|
include Smash::CloudPowers::AwsResources
|
22
|
-
# Various helper methods
|
23
|
-
include Smash::CloudPowers::Helper
|
24
|
-
# Gathers data about an instance, itself
|
25
|
-
include Smash::CloudPowers::SelfAwareness
|
26
18
|
# Store files
|
27
19
|
include Smash::CloudPowers::Storage
|
28
20
|
# Communication modules
|
29
21
|
include Smash::CloudPowers::Synapse
|
30
22
|
# CRUD on Nodes, which are individual instances
|
31
23
|
include Smash::CloudPowers::Node
|
32
|
-
# Dynamically Builds and loads a Workflow into a class at runtime
|
33
|
-
include Smash::CloudPowers::WorkflowFactory
|
34
24
|
end
|
35
25
|
end
|
@@ -1,12 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require 'cloud_powers/auth'
|
2
|
+
require 'cloud_powers/helpers'
|
3
|
+
require 'cloud_powers/zenv'
|
4
4
|
|
5
5
|
module Smash
|
6
6
|
module CloudPowers
|
7
7
|
module AwsResources
|
8
8
|
include Smash::CloudPowers::Auth
|
9
|
-
include Smash::CloudPowers::
|
9
|
+
include Smash::CloudPowers::Helpers
|
10
10
|
include Smash::CloudPowers::Zenv
|
11
11
|
|
12
12
|
# Get the region from the environment/context or use a default region for AWS API calls.
|
@@ -89,6 +89,23 @@ module Smash
|
|
89
89
|
@kinesis ||= Aws::Kinesis::Client.new(config)
|
90
90
|
end
|
91
91
|
|
92
|
+
# Create a QueuePoller for an already created SQS Queue
|
93
|
+
# (CloudPowers::Synapse::Board)
|
94
|
+
#
|
95
|
+
# Parameters
|
96
|
+
# * :url +String+ - the url for the Queue/Board
|
97
|
+
# * :client <tt>Aws::SQS::Client</tt>
|
98
|
+
#
|
99
|
+
# Returns
|
100
|
+
# <tt>Aws::SQS::QueuePoller</tt>
|
101
|
+
#
|
102
|
+
# Notes
|
103
|
+
# * this is different from the other methods in here, in that it doesn't
|
104
|
+
# create an i-var on your class.
|
105
|
+
def queue_poller(url:, client: sqs)
|
106
|
+
Aws::SQS::QueuePoller.new(url, client: client)
|
107
|
+
end
|
108
|
+
|
92
109
|
# Get or create an S3 client and cache that client so that a Context is more well tied together
|
93
110
|
#
|
94
111
|
# Parameters
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'cloud_powers/helpers'
|
2
|
+
|
3
|
+
module Smash
|
4
|
+
module CloudPowers
|
5
|
+
# Give an object an
|
6
|
+
# Active Record-like interface, with a twist. Instead of a database, we're
|
7
|
+
# using cloud resources. This module includes handy methods that can act
|
8
|
+
# like before and after hooks, for object instantiation and cloud-resource
|
9
|
+
# creation. To use the module, you have to participate in the interface,
|
10
|
+
# which means you have to follow <i><b>a few rules</b></i>:
|
11
|
+
# 1. your +initialize+ method can take a list of keyword arguments or a +Hash+
|
12
|
+
# for configuration
|
13
|
+
# 2. your resource class has a <tt>create_resource</tt> method that can
|
14
|
+
# deal with making the http request for creating the resource in the cloud
|
15
|
+
# 3. your class extends this module
|
16
|
+
module Creatable
|
17
|
+
include Smash::CloudPowers::Helpers
|
18
|
+
|
19
|
+
def self.included base
|
20
|
+
base.send :include, AfterHooks
|
21
|
+
base.extend BeforeHooks
|
22
|
+
end
|
23
|
+
|
24
|
+
module BeforeHooks
|
25
|
+
# +Boolean+ - tells if this resource is mapped to a resource in the cloud
|
26
|
+
attr_accessor :saved
|
27
|
+
|
28
|
+
# A +before_hook+ style method that allows you to do things after you
|
29
|
+
# instantiate the resource's object but <b>before</b> you create the
|
30
|
+
# resource, in the cloud. Because we're likely to be in the middle of
|
31
|
+
# requesting a resource be requested, in the cloud, this method gives us
|
32
|
+
# a means to do some checking, linking and/or setup before we make a request.
|
33
|
+
#
|
34
|
+
# Parameters
|
35
|
+
# * +Hash+ or keyword argument(s) - configuration
|
36
|
+
#
|
37
|
+
# * +Block+ (optional) - your optional before_hook that runs before you've
|
38
|
+
# instantiated your object, yielding the new instance to you, to run in your block.
|
39
|
+
#
|
40
|
+
# Returns
|
41
|
+
# +Object+ - a new instance of the class that extended this module
|
42
|
+
def build(name:, **config)
|
43
|
+
new_resource = self.new(name: name, **config)
|
44
|
+
yield new_resource if block_given?
|
45
|
+
new_resource
|
46
|
+
end
|
47
|
+
|
48
|
+
# An +after_hook+ style method that allows you to do things after you
|
49
|
+
# instantiate the resource's object, but before you create the resource,
|
50
|
+
# in the cloud. Because we're likely to be in the middle of requesting to
|
51
|
+
# create a resource, in the cloud, this method
|
52
|
+
# gives us a means to do some checking or setup after we make a request.
|
53
|
+
#
|
54
|
+
# Parameters
|
55
|
+
# * +Hash+ or keyword argument(s) - configuration
|
56
|
+
#
|
57
|
+
# * +Block+ (optional) - your optional after_hook that runs after you've
|
58
|
+
# created your resource(s) in the cloud, yielding the new instance to you,
|
59
|
+
# to run in your block.
|
60
|
+
#
|
61
|
+
# Returns
|
62
|
+
# +Object+ - a new instance of the class that extended this module
|
63
|
+
#
|
64
|
+
# Notes
|
65
|
+
# * See <tt>#build</tt>
|
66
|
+
# * See <tt>#save!</tt>
|
67
|
+
# * See <tt>CloudPowers::Helpers::LogicHelp#instance_attr_accessor</tt>
|
68
|
+
# * See <tt>CloudPowers::Helpers::LogicHelp#attr_map</tt>
|
69
|
+
def create!(name:, **config)
|
70
|
+
new_resource = self.build(name: name, **config)
|
71
|
+
|
72
|
+
new_resource.attr_map(config) do |config_key, config_value|
|
73
|
+
new_resource.instance_attr_accessor new_resource.to_snake(config_key)
|
74
|
+
config_value
|
75
|
+
end
|
76
|
+
|
77
|
+
new_resource.save!
|
78
|
+
|
79
|
+
yield new_resource if block_given?
|
80
|
+
new_resource
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
module AfterHooks
|
85
|
+
# Alternative to <tt>save!()</tt>. This predicate method is based off
|
86
|
+
# the <tt>@linked</tt> i-var and is set to true after it has been confirmed
|
87
|
+
# that this resource is a good map to the resource in the cloud.
|
88
|
+
#
|
89
|
+
# Returns
|
90
|
+
# * +Boolean+
|
91
|
+
def linked?
|
92
|
+
!!@linked
|
93
|
+
end
|
94
|
+
|
95
|
+
# An +after_hook+ style method that sends a reqeust to your custom implementation
|
96
|
+
# of the <tt>create_resource</tt> methodallows you to do things after you
|
97
|
+
# create the resource, in the cloud. This method relies on you having
|
98
|
+
# a <tt>create_resource</tt> method that can handle every aspect of creating
|
99
|
+
# your resource. If this piece of the contract isn't obeyed, you will
|
100
|
+
# receive a <tt>NoMethodError</tt>.
|
101
|
+
#
|
102
|
+
# Returns
|
103
|
+
# +Boolean+ - +true+ if the resource
|
104
|
+
def save!
|
105
|
+
resp = create_resource if self.respond_to? :create_resource
|
106
|
+
@saved = !resp.nil?
|
107
|
+
end
|
108
|
+
|
109
|
+
# Find out if the resource was created
|
110
|
+
#
|
111
|
+
# Returns
|
112
|
+
# +Boolean+
|
113
|
+
def saved?
|
114
|
+
!!@saved
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
|