fauna 0.0.0 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig ADDED
Binary file
data/CHANGELOG ADDED
@@ -0,0 +1,6 @@
1
+
2
+
3
+ v0.1. Refactor resource hierarchy. Add cache. Flesh out ActiveModel
4
+ support.
5
+
6
+ v0.0. First release.
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+
3
+ gem 'rake'
4
+ gem 'jruby-openssl', :platform => :jruby
5
+
6
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,12 @@
1
+ Copyright 2013 Fauna, Inc.
2
+
3
+ Licensed under the Mozilla Public License, Version 2.0 (the "License"); you may
4
+ not use this software except in compliance with the License. You may obtain a
5
+ copy of the License at
6
+
7
+ http://mozilla.org/MPL/2.0/
8
+
9
+ Unless required by applicable law or agreed to in writing, software distributed
10
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
12
+ specific language governing permissions and limitations under the License.
data/Manifest ADDED
@@ -0,0 +1,31 @@
1
+ CHANGELOG
2
+ Gemfile
3
+ LICENSE
4
+ Manifest
5
+ README.md
6
+ Rakefile
7
+ fauna.gemspec
8
+ lib/fauna.rb
9
+ lib/fauna/client.rb
10
+ lib/fauna/connection.rb
11
+ lib/fauna/ddl.rb
12
+ lib/fauna/model.rb
13
+ lib/fauna/model/class.rb
14
+ lib/fauna/model/follow.rb
15
+ lib/fauna/model/publisher.rb
16
+ lib/fauna/model/timeline.rb
17
+ lib/fauna/model/user.rb
18
+ lib/fauna/rails.rb
19
+ lib/fauna/resource.rb
20
+ test/client_test.rb
21
+ test/connection_test.rb
22
+ test/fixtures.rb
23
+ test/model/association_test.rb
24
+ test/model/class_test.rb
25
+ test/model/follow_test.rb
26
+ test/model/publisher_test.rb
27
+ test/model/timeline_test.rb
28
+ test/model/user_test.rb
29
+ test/model/validation_test.rb
30
+ test/readme_test.rb
31
+ test/test_helper.rb
data/README.md ADDED
@@ -0,0 +1,285 @@
1
+ # Fauna
2
+
3
+ Ruby client for the [Fauna](http://fauna.org) API.
4
+
5
+ ## Installation
6
+
7
+ The Fauna ruby client is distributed as a gem. Install it via:
8
+
9
+ $ gem install fauna
10
+
11
+ Or if you use Bundler, add it to your application's `Gemfile`:
12
+
13
+ gem 'fauna'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ ## Compatibility
20
+
21
+ Tested and compatible with MRI 1.9.3. Other Rubies may also work.
22
+
23
+ ## Basic Usage
24
+
25
+ First, require the gem:
26
+
27
+ ```ruby
28
+ require "rubygems"
29
+ require "fauna"
30
+ ```
31
+
32
+ ### Configuring the API
33
+
34
+ All API requests start with an instance of `Fauna::Connection`.
35
+
36
+ Creating a connection requires either a token, a publisher key, a
37
+ client key, or the publisher's email and password.
38
+
39
+ Let's use the email and password to get a publisher key:
40
+
41
+ ```ruby
42
+ root = Fauna::Connection.new(email: "publisher@example.com", password: "secret")
43
+ publisher_key = root.post("keys/publisher")['resource']['key']
44
+ ```
45
+
46
+ Now we can make a global publisher-level connection:
47
+
48
+ ```ruby
49
+ $fauna = Fauna::Connection.new(publisher_key: publisher_key)
50
+ ```
51
+
52
+ You can optionally configure a `logger` on the connection to ease
53
+ debugging:
54
+
55
+ ```ruby
56
+ require "logger"
57
+ $fauna = Fauna::Connection.new(publisher_key: publisher_key, logger:
58
+ Logger.new(STDERR))
59
+ ```
60
+
61
+ ### Client Contexts
62
+
63
+ The easiest way to work with a connection is to open up a *client
64
+ context*, and then manipulate resources within that context:
65
+
66
+ ```ruby
67
+ Fauna::Client.context($fauna) do
68
+ user = Fauna::User.create!(name: "Taran", email: "taran@example.com")
69
+ user.data["profession"] = "Pigkeeper"
70
+ user.save!
71
+ user.destroy
72
+ end
73
+ ```
74
+
75
+ By working within a context, not only are you able to use a more
76
+ convienient, object-oriented API, you also gain the advantage of
77
+ in-process caching.
78
+
79
+ Within a context block, requests for a resource that has already been
80
+ loaded via a previous request will be returned from the cache and no
81
+ query will be issued. This substantially lowers network overhead,
82
+ since Fauna makes an effort to return related resources as part of
83
+ every response.
84
+
85
+ ### Fauna::Resource
86
+
87
+ All instances of fauna classes have built-in accessors for common
88
+ fields:
89
+
90
+ ```ruby
91
+ Fauna::Client.context($fauna) do
92
+ user = Fauna::User.create(external_id: "taran77", name: "Taran")
93
+
94
+ # fields
95
+ user.ref # => "users/123"
96
+ user.ts # => 1359579766996758
97
+ user.deleted # => false
98
+ user.external_id # => "taran77"
99
+
100
+ # data and references
101
+ user.data # => {}
102
+ user.references # => {}
103
+
104
+ # standard timelines
105
+ user.changes
106
+ user.user_follows
107
+ user.user_followers
108
+ user.instance_follows
109
+ user.instance_followers
110
+ user.local
111
+ end
112
+ ```
113
+
114
+ ## Rails Usage
115
+
116
+ Fauna provides ActiveModel-compatible classes that can be used
117
+ directly in Rails.
118
+
119
+ Fauna also provides a Rails helper that sets up a default context in
120
+ controllers, based on credentials in `config/fauna.yml`:
121
+
122
+ ```yaml
123
+ development:
124
+ email: taran@example.com
125
+ password: secret
126
+ test:
127
+ email: taran@example.com
128
+ password: secret
129
+ ```
130
+
131
+ Then, in `config/initializers/fauna.rb`:
132
+
133
+ ```ruby
134
+ require "fauna/rails"
135
+
136
+ Fauna.schema do
137
+ # See below for schema setup
138
+ end
139
+ ```
140
+
141
+ ### Setting Up the Schema
142
+
143
+ First, create some Ruby classes to model your domain. They must
144
+ inherit from the `Fauna::Class` base class:
145
+
146
+ ```ruby
147
+ # Create a custom Pig class.
148
+ class Pig < Fauna::Class
149
+ # Fields can be configured dynamically
150
+ field :name, :title
151
+ end
152
+
153
+ # Create a custom Vision class
154
+ class Vision < Fauna::Class
155
+ field :pronouncement
156
+ reference :pig
157
+ end
158
+ ```
159
+
160
+ Fields and references can be configured dynamically, but the classes
161
+ and timelines themselves must be configured with an additional
162
+ `Fauna.schema` block (normally placed in
163
+ `config/initializers/fauna.rb`):
164
+
165
+ ```ruby
166
+ Fauna.schema do
167
+ with Pig do
168
+ # Add a custom timeline
169
+ timeline :visions
170
+ end
171
+
172
+ with Vision
173
+ end
174
+ ```
175
+
176
+ Install your schema on the server via a Rake task or the Rails
177
+ console:
178
+
179
+ ```ruby
180
+ Fauna::Client.context(Fauna.connection) do
181
+ Fauna.migrate_schema!
182
+ end
183
+ ```
184
+
185
+ Make sure to do this at least once, as well as every time you change
186
+ the schema definition:
187
+
188
+ ### Users Class
189
+
190
+ ```ruby
191
+ class Fauna::User
192
+ # Extend the User class with a custom field
193
+ field :pockets
194
+ end
195
+
196
+ # Create a user, fill their pockets, and delete them.
197
+ Fauna::Client.context($fauna) do
198
+ taran = Fauna::User.new(
199
+ name: "Taran",
200
+ email: "taran@example.com",
201
+ password: "secret")
202
+
203
+ taran.save!
204
+ taran.pockets = "Piggy treats"
205
+ taran.save!
206
+ taran.destroy
207
+ end
208
+ ```
209
+
210
+ ### Custom Classes
211
+
212
+ ```ruby
213
+ # Create, find, update, and destroy Pigs.
214
+ Fauna::Client.context($fauna) do
215
+ @pig = Pig.create!(name: "Henwen", external_id: "henwen")
216
+
217
+ @pig = Pig.find(@pig.ref)
218
+ @pig.update(title: "Oracular Swine")
219
+
220
+ @pig.title = "Most Illustrious Oracular Swine"
221
+ @pig.save!
222
+
223
+ @pig.destroy
224
+ end
225
+ ```
226
+
227
+ ### Timelines
228
+
229
+ [Timelines](https://fauna.org/API#timelines) are high-cardinality,
230
+ bidirectional event collections. Timelines must be declared in the
231
+ Schema.
232
+
233
+ ```ruby
234
+ Fauna::Client.context($fauna) do
235
+ @pig = Pig.create!(name: "Henwen", external_id: "henwen")
236
+
237
+ @vision = Vision.create!(pronouncement: "In an ominous tower...")
238
+ @pig.visions.add @vision
239
+ @pig.visions.page.events.first.resource # => @vision
240
+ end
241
+ ```
242
+
243
+ ### References
244
+
245
+ References are single or low-cardinality, unidirectional, and have no
246
+ event log. They are declared dynamically, in the class.
247
+
248
+ ```ruby
249
+ class Vision
250
+ # References can be configured dynamically, like fields
251
+ reference :pig
252
+ end
253
+
254
+ Fauna::Client.context($fauna) do
255
+ @vision.pig # => @pig
256
+ @vision.pig_ref # => "instances/1235921393191239"
257
+ end
258
+ ```
259
+
260
+ ## Further Reading
261
+
262
+ Please see the Fauna [REST Documentation](https://fauna.org/API) for a
263
+ complete API reference, or look in
264
+ [`/tests`](https://github.com/fauna/fauna-ruby/tree/master/test) for
265
+ more examples.
266
+
267
+ ## Contributing
268
+
269
+ GitHub pull requests are very welcome.
270
+
271
+ ## LICENSE
272
+
273
+ Copyright 2013 [Fauna, Inc.](https://fauna.org/)
274
+
275
+ Licensed under the Mozilla Public License, Version 2.0 (the
276
+ "License"); you may not use this software except in compliance with
277
+ the License. You may obtain a copy of the License at
278
+
279
+ [http://mozilla.org/MPL/2.0/](http://mozilla.org/MPL/2.0/)
280
+
281
+ Unless required by applicable law or agreed to in writing, software
282
+ distributed under the License is distributed on an "AS IS" BASIS,
283
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
284
+ implied. See the License for the specific language governing
285
+ permissions and limitations under the License.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'echoe'
2
+
3
+ Echoe.new("fauna") do |p|
4
+ p.author = "Fauna, Inc."
5
+ p.project = "fauna"
6
+ p.summary = "Official Ruby client for the Fauna API."
7
+ p.retain_gemspec = true
8
+ p.dependencies = ["activemodel", "activesupport", "rest-client", "json"]
9
+ p.development_dependencies = ["mocha", "echoe", "minitest"]
10
+ end
11
+
12
+ task :beautify do
13
+ require "ruby-beautify"
14
+ Dir["**/*rb"].each do |filename|
15
+ s = RBeautify.beautify_string(:ruby, File.read(filename))
16
+ File.write(filename, s) unless s.empty?
17
+ end
18
+ end
19
+
20
+ task :prerelease => [:manifest, :test, :install]
data/fauna.gemspec ADDED
@@ -0,0 +1,53 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "fauna"
5
+ s.version = "0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Fauna, Inc."]
9
+ s.cert_chain = ["/Users/eweaver/cloudburst/configuration/gem_certificates/evan_weaver-original-public_cert.pem"]
10
+ s.date = "2013-02-08"
11
+ s.description = "Official Ruby client for the Fauna API."
12
+ s.email = ""
13
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.md", "lib/fauna.rb", "lib/fauna/client.rb", "lib/fauna/connection.rb", "lib/fauna/ddl.rb", "lib/fauna/model.rb", "lib/fauna/model/class.rb", "lib/fauna/model/follow.rb", "lib/fauna/model/publisher.rb", "lib/fauna/model/timeline.rb", "lib/fauna/model/user.rb", "lib/fauna/rails.rb", "lib/fauna/resource.rb"]
14
+ s.files = ["CHANGELOG", "Gemfile", "LICENSE", "Manifest", "README.md", "Rakefile", "fauna.gemspec", "lib/fauna.rb", "lib/fauna/client.rb", "lib/fauna/connection.rb", "lib/fauna/ddl.rb", "lib/fauna/model.rb", "lib/fauna/model/class.rb", "lib/fauna/model/follow.rb", "lib/fauna/model/publisher.rb", "lib/fauna/model/timeline.rb", "lib/fauna/model/user.rb", "lib/fauna/rails.rb", "lib/fauna/resource.rb", "test/client_test.rb", "test/connection_test.rb", "test/fixtures.rb", "test/model/association_test.rb", "test/model/class_test.rb", "test/model/follow_test.rb", "test/model/publisher_test.rb", "test/model/timeline_test.rb", "test/model/user_test.rb", "test/model/validation_test.rb", "test/readme_test.rb", "test/test_helper.rb"]
15
+ s.homepage = "http://fauna.github.com/fauna/"
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Fauna", "--main", "README.md"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = "fauna"
19
+ s.rubygems_version = "1.8.23"
20
+ s.signing_key = "/Users/eweaver/cloudburst/configuration/gem_certificates/evan_weaver-original-private_key.pem"
21
+ s.summary = "Official Ruby client for the Fauna API."
22
+ s.test_files = ["test/client_test.rb", "test/connection_test.rb", "test/model/association_test.rb", "test/model/class_test.rb", "test/model/follow_test.rb", "test/model/publisher_test.rb", "test/model/timeline_test.rb", "test/model/user_test.rb", "test/model/validation_test.rb", "test/readme_test.rb", "test/test_helper.rb"]
23
+
24
+ if s.respond_to? :specification_version then
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
28
+ s.add_runtime_dependency(%q<activemodel>, [">= 0"])
29
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
30
+ s.add_runtime_dependency(%q<rest-client>, [">= 0"])
31
+ s.add_runtime_dependency(%q<json>, [">= 0"])
32
+ s.add_development_dependency(%q<mocha>, [">= 0"])
33
+ s.add_development_dependency(%q<echoe>, [">= 0"])
34
+ s.add_development_dependency(%q<minitest>, [">= 0"])
35
+ else
36
+ s.add_dependency(%q<activemodel>, [">= 0"])
37
+ s.add_dependency(%q<activesupport>, [">= 0"])
38
+ s.add_dependency(%q<rest-client>, [">= 0"])
39
+ s.add_dependency(%q<json>, [">= 0"])
40
+ s.add_dependency(%q<mocha>, [">= 0"])
41
+ s.add_dependency(%q<echoe>, [">= 0"])
42
+ s.add_dependency(%q<minitest>, [">= 0"])
43
+ end
44
+ else
45
+ s.add_dependency(%q<activemodel>, [">= 0"])
46
+ s.add_dependency(%q<activesupport>, [">= 0"])
47
+ s.add_dependency(%q<rest-client>, [">= 0"])
48
+ s.add_dependency(%q<json>, [">= 0"])
49
+ s.add_dependency(%q<mocha>, [">= 0"])
50
+ s.add_dependency(%q<echoe>, [">= 0"])
51
+ s.add_dependency(%q<minitest>, [">= 0"])
52
+ end
53
+ end
data/lib/fauna.rb ADDED
@@ -0,0 +1,98 @@
1
+ require "json"
2
+ require "logger"
3
+
4
+ require "restclient"
5
+ require "active_model"
6
+ require "active_support/inflector"
7
+ require "active_support/core_ext/module/delegation"
8
+ require "active_support/core_ext/hash/slice"
9
+
10
+ module Fauna
11
+ class Invalid < RuntimeError
12
+ end
13
+
14
+ class NotFound < RuntimeError
15
+ end
16
+
17
+ class MissingMigration < RuntimeError
18
+ end
19
+ end
20
+
21
+ require "fauna/connection"
22
+ require "fauna/client"
23
+ require "fauna/resource"
24
+ require "fauna/model"
25
+ require "fauna/model/class"
26
+ require "fauna/model/follow"
27
+ require "fauna/model/publisher"
28
+ require "fauna/model/timeline"
29
+ require "fauna/model/user"
30
+ require "fauna/ddl"
31
+
32
+ module Fauna
33
+
34
+ DEFAULT_BLOCK = proc do
35
+ with User, class_name: "users"
36
+ with User::Settings, class_name: "users/settings"
37
+ with Follow, class_name: "follows"
38
+ with TimelinePage, class_name: "timelines"
39
+ with TimelineSettings, class_name: "timelines/settings"
40
+ with ClassSettings, class_name: "classes"
41
+ with Publisher, class_name: "publisher"
42
+ end
43
+
44
+ def self.configure_schema!
45
+ @_classes = {}
46
+ @schema = Fauna::DDL.new
47
+ @_blocks.each { |blk| @schema.instance_eval(&blk) }
48
+ @schema.configure!
49
+ nil
50
+ end
51
+
52
+ def self.schema(&block)
53
+ @_blocks << block
54
+ configure_schema!
55
+ end
56
+
57
+
58
+ def self.reset_schema!
59
+ @_blocks = [DEFAULT_BLOCK]
60
+ configure_schema!
61
+ end
62
+
63
+ def self.migrate_schema!
64
+ @schema.load!
65
+ nil
66
+ end
67
+
68
+ # these should be private to the gem
69
+
70
+ def self.exists_class_for_name?(class_name)
71
+ !!@_classes[class_name]
72
+ end
73
+
74
+ def self.add_class(class_name, klass)
75
+ klass.fauna_class_name = class_name.to_s
76
+ @_classes.delete_if { |_, v| v == klass }
77
+ @_classes[class_name.to_s] = klass
78
+ end
79
+
80
+ def self.class_for_name(class_name)
81
+ @_classes[class_name] ||=
82
+ if class_name =~ %r{^classes/[^/]+$}
83
+ klass = begin $1.classify.constantize rescue NameError; nil end
84
+ if klass.nil? || klass >= Fauna::Class || klass.fauna_class_name
85
+ klass = ::Class.new(Fauna::Class)
86
+ end
87
+
88
+ klass.fauna_class_name = class_name
89
+ klass
90
+ else
91
+ ::Class.new(Fauna::Resource)
92
+ end
93
+ end
94
+
95
+ # apply the default schema so that the built-in classes work
96
+
97
+ reset_schema!
98
+ end