fauna 0.0.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.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