README.md in cistern-0.5.4 vs README.md in cistern-0.5.6
- old
+ new
@@ -9,175 +9,200 @@
### Service
This represents the remote service that you are wrapping. If the service name is 'foo' then a good name is 'Foo::Client'.
-Service initialization will only accept parameters enumerated by ```requires``` and ```recognizes```. ```model```, ```collection```, and ```request``` enumerate supported features and require them directly within the context of the ```model_path``` and ```request_path```.
+#### Requests
-```Mock.data``` is commonly used to store mock data. It is often easiest to use identity to raw response mappings within the ```Mock.data``` hash.
+Requests are enumerated using the ```request``` method and required immediately via the relative path specified via ```request_path```.
-```ruby
+ class Foo::Client < Cistern::Service
+ request_path "my-foo/requests"
-class Foo::Client < Cistern::Service
+ request :get_bar # require my-foo/requests/get_bar.rb
+ request :get_bars # require my-foo/requests/get_bars.rb
- model_path "foo/models"
- request_path "foo/requests"
+ class Real
+ def request(url)
+ Net::HTTP.get(url)
+ end
+ end
+ end
- model :bar
- collection :bars
- request :create_bar
- request :get_bar
- request :get_bars
- requires :hmac_id, :hmac_secret
- recognizes :host
+<!--todo move to a request section-->
+A request is method defined within the context of service and mode (Real or Mock). Defining requests within the service mock class is optional.
- class Real
- def initialize(options={})
- # setup connection
- end
- end
+ # my-foo/requests/get_bar.rb
+ class Foo::Client
+ class Real
+ def get_bar(bar_id)
+ request("http://example.org/bar/#{bar_id}")
+ end
+ end # Real
- class Mock
- def self.data
- @data ||= {
- :bars => {},
- }
- end
+ # optional, but encouraged
+ class Mock
+ def get_bars
+ # do some mock things
+ end
+ end # Mock
+ end # Foo::client
- def self.reset!
- @data = nil
+All declared requests can be listed via ```Cistern::Service#requests```.
+
+ Foo::Client.requests # => [:get_bar, :get_bars]
+
+#### Models and Collections
+
+Models and collections have declaration semantics similar to requests. Models and collections are enumerated via ```model``` and ```collection``` respectively.
+
+ class Foo::Client < Cistern::Service
+ model_path "my-foo/models"
+
+ model :bar # require my-foo/models/bar.rb
+ collection :bars # require my-foo/models/bars.rb
end
- def data
- self.class.data
+#### Initialization
+
+Service initialization parameters are enumerated by ```requires``` and ```recognizes```. ```recognizes``` parameters are optional.
+
+ class Foo::Client < Cistern::Service
+ requires :hmac_id, :hmac_secret
+ recognizes :url
end
- def initialize(options={})
- # setup mock data
- end
- end
-end
-```
+ # Acceptable
+ Foo::Client.new(hmac_id: "1", hmac_secret: "2") # Foo::Client::Real
+ Foo::Client.new(hmac_id: "1", hmac_secret: "2", url: "http://example.org") # Foo::Client::Real
+ # ArgumentError
+ Foo::Client.new(hmac_id: "1", url: "http://example.org")
+ Foo::Client.new(hmac_id: "1")
+
+
+#### Mocking
+
+Cistern strongly encourages you to generate mock support for service. Mocking can be enabled using ```mock!```.
+
+ Foo::Client.mocking? # falsey
+ real = Foo::Client.new # Foo::Client::Real
+ Foo::Client.mock!
+ Foo::Client.mocking? # true
+ fake = Foo::Client.new # Foo::Client::Mock
+ Foo::Client.unmock!
+ Foo::Client.mocking? # false
+ real.is_a?(Foo::Client::Real) # true
+ fake.is_a?(Foo::Client::Mock) # true
+
+
### Model
```connection``` represents the associated ```Foo::Client``` instance.
-```ruby
+ class Foo::Client::Bar < Cistern::Model
+ identity :id
-class Foo::Client::Bar < Cistern::Model
- identity :id
+ attribute :flavor
+ attribute :keypair_id, aliases: "keypair", squash: "id"
+ attribute :private_ips, type: :array
- attribute :flavor
- attribute :keypair_id, aliases: "keypair", squash: "id"
- attribute :private_ips, type: :array
+ def destroy
+ params = {
+ "id" => self.identity
+ }
+ self.connection.destroy_bar(params).body["request"]
+ end
- def destroy
- params = {
- "id" => self.identity
- }
- self.connection.destroy_bar(params).body["request"]
- end
+ def save
+ requires :keypair_id
- def save
- requires :keypair_id
+ params = {
+ "keypair" => self.keypair_id,
+ "bar" => {
+ "flavor" => self.flavor,
+ },
+ }
- params = {
- "keypair" => self.keypair_id,
- "bar" => {
- "flavor" => self.flavor,
- },
- }
+ if new_record?
+ merge_attributes(connection.create_bar(params).body["bar"])
+ else
+ requires :identity
- if new_record?
- merge_attributes(connection.create_bar(params).body["bar"])
- else
- requires :identity
-
- merge_attributes(connection.update_bar(params).body["bar"])
+ merge_attributes(connection.update_bar(params).body["bar"])
+ end
+ end
end
- end
-end
-```
-
### Collection
```model``` tells Cistern which class is contained within the collection. ```Cistern::Collection``` inherits from ```Array``` and lazy loads where applicable.
-```ruby
+ class Foo::Client::Bars < Cistern::Collection
-class Foo::Client::Bars < Cistern::Collection
+ model Foo::Client::Bar
- model Foo::Client::Bar
+ def all(params = {})
+ response = connection.get_bars(params)
- def all(params = {})
- response = connection.get_bars(params)
+ data = response.body
- data = response.body
+ self.load(data["bars"]) # store bar records in collection
+ self.merge_attributes(data) # store any other attributes of the response on the collection
+ end
- self.load(data["bars"]) # store bar records in collection
- self.merge_attributes(data) # store any other attributes of the response on the collection
- end
+ def discover(provisioned_id, options={})
+ params = {
+ "provisioned_id" => provisioned_id,
+ }
+ params.merge!("location" => options[:location]) if options.key?(:location)
- def discover(provisioned_id, options={})
- params = {
- "provisioned_id" => provisioned_id,
- }
- params.merge!("location" => options[:location]) if options.key?(:location)
+ connection.requests.new(connection.discover_bar(params).body["request"])
+ end
- connection.requests.new(connection.discover_bar(params).body["request"])
- end
-
- def get(id)
- if data = connection.get_bar("id" => id).body["bar"]
- new(data)
- else
- nil
+ def get(id)
+ if data = connection.get_bar("id" => id).body["bar"]
+ new(data)
+ else
+ nil
+ end
+ end
end
- end
-end
-```
-
### Request
-```ruby
+ module Foo
+ class Client
+ class Real
+ def create_bar(options={})
+ request(
+ :body => {"bar" => options},
+ :method => :post,
+ :path => '/bar'
+ )
+ end
+ end # Real
-module Foo
- class Client
- class Real
- def create_bar(options={})
- request(
- :body => {"bar" => options},
- :method => :post,
- :path => '/bar'
- )
- end
- end # Real
+ class Mock
+ def create_bar(options={})
+ id = Foo.random_hex(6)
- class Mock
- def create_bar(options={})
- id = Foo.random_hex(6)
+ bar = {
+ "id" => id
+ }.merge(options)
- bar = {
- "id" => id
- }.merge(options)
+ self.data[:bars][id]= bar
- self.data[:bars][id]= bar
-
- response(
- :body => {"bar" => bar},
- :status => 201,
- :path => '/bar',
- )
- end
- end # Mock
- end # Client
-end # Foo
-
-```
+ response(
+ :body => {"bar" => bar},
+ :status => 201,
+ :path => '/bar',
+ )
+ end
+ end # Mock
+ end # Client
+ end # Foo
## Examples
* [zendesk2](https://github.com/lanej/zendesk2)