smooth-io 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.rvmrc +1 -0
- data/.travis +6 -0
- data/CNAME +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +147 -0
- data/Guardfile +5 -0
- data/LICENSE.md +22 -0
- data/README.md +33 -0
- data/Rakefile +10 -0
- data/bin/smooth +8 -0
- data/doc/presenters.md +47 -0
- data/lib/smooth.rb +56 -0
- data/lib/smooth/adapters/rails_cache.rb +19 -0
- data/lib/smooth/adapters/redis_cache.rb +36 -0
- data/lib/smooth/backends/active_record.rb +56 -0
- data/lib/smooth/backends/base.rb +84 -0
- data/lib/smooth/backends/file.rb +80 -0
- data/lib/smooth/backends/redis.rb +71 -0
- data/lib/smooth/backends/redis_namespace.rb +10 -0
- data/lib/smooth/backends/rest_client.rb +29 -0
- data/lib/smooth/collection.rb +236 -0
- data/lib/smooth/collection/cacheable.rb +12 -0
- data/lib/smooth/collection/query.rb +14 -0
- data/lib/smooth/endpoint.rb +23 -0
- data/lib/smooth/meta_data.rb +33 -0
- data/lib/smooth/meta_data/application.rb +29 -0
- data/lib/smooth/meta_data/inspector.rb +67 -0
- data/lib/smooth/model.rb +93 -0
- data/lib/smooth/presentable.rb +76 -0
- data/lib/smooth/presentable/api_endpoint.rb +49 -0
- data/lib/smooth/presentable/chain.rb +46 -0
- data/lib/smooth/presentable/controller.rb +39 -0
- data/lib/smooth/queryable.rb +35 -0
- data/lib/smooth/queryable/converter.rb +8 -0
- data/lib/smooth/queryable/settings.rb +23 -0
- data/lib/smooth/resource.rb +10 -0
- data/lib/smooth/version.rb +3 -0
- data/smooth-io.gemspec +35 -0
- data/spec/blueprints/people.rb +4 -0
- data/spec/environment.rb +17 -0
- data/spec/lib/backends/active_record_spec.rb +17 -0
- data/spec/lib/backends/base_spec.rb +77 -0
- data/spec/lib/backends/file_spec.rb +46 -0
- data/spec/lib/backends/multi_spec.rb +47 -0
- data/spec/lib/backends/redis_namespace_spec.rb +41 -0
- data/spec/lib/backends/redis_spec.rb +40 -0
- data/spec/lib/backends/rest_client_spec.rb +0 -0
- data/spec/lib/collection/query_spec.rb +9 -0
- data/spec/lib/collection_spec.rb +87 -0
- data/spec/lib/examples/cacheable_collection_spec.rb +27 -0
- data/spec/lib/examples/smooth_model_spec.rb +13 -0
- data/spec/lib/meta_data/application_spec.rb +43 -0
- data/spec/lib/meta_data_spec.rb +32 -0
- data/spec/lib/model_spec.rb +54 -0
- data/spec/lib/presentable/api_endpoint_spec.rb +54 -0
- data/spec/lib/presentable_spec.rb +80 -0
- data/spec/lib/queryable/converter_spec.rb +104 -0
- data/spec/lib/queryable_spec.rb +27 -0
- data/spec/lib/resource_spec.rb +17 -0
- data/spec/lib/smooth_spec.rb +13 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/support/models.rb +28 -0
- data/spec/support/schema.rb +16 -0
- metadata +359 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3-p392@smooth --create
|
data/.travis
ADDED
data/CNAME
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
smooth.io
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
smooth (0.0.5)
|
5
|
+
activerecord (>= 3.2.12)
|
6
|
+
activesupport (>= 3.2.12)
|
7
|
+
faye
|
8
|
+
redis
|
9
|
+
redis-namespace
|
10
|
+
sinatra
|
11
|
+
squeel
|
12
|
+
typhoeus
|
13
|
+
virtus (= 0.5.5)
|
14
|
+
|
15
|
+
GEM
|
16
|
+
remote: https://rubygems.org/
|
17
|
+
specs:
|
18
|
+
activemodel (3.2.13)
|
19
|
+
activesupport (= 3.2.13)
|
20
|
+
builder (~> 3.0.0)
|
21
|
+
activerecord (3.2.13)
|
22
|
+
activemodel (= 3.2.13)
|
23
|
+
activesupport (= 3.2.13)
|
24
|
+
arel (~> 3.0.2)
|
25
|
+
tzinfo (~> 0.3.29)
|
26
|
+
activesupport (3.2.13)
|
27
|
+
i18n (= 0.6.1)
|
28
|
+
multi_json (~> 1.0)
|
29
|
+
addressable (2.3.5)
|
30
|
+
arel (3.0.2)
|
31
|
+
backports (3.3.4)
|
32
|
+
builder (3.0.4)
|
33
|
+
coderay (1.0.9)
|
34
|
+
cookiejar (0.3.0)
|
35
|
+
descendants_tracker (0.0.1)
|
36
|
+
diff-lcs (1.2.1)
|
37
|
+
em-http-request (1.1.0)
|
38
|
+
addressable (>= 2.3.4)
|
39
|
+
cookiejar
|
40
|
+
em-socksify (>= 0.3)
|
41
|
+
eventmachine (>= 1.0.3)
|
42
|
+
http_parser.rb (>= 0.6.0.beta.2)
|
43
|
+
em-socksify (0.3.0)
|
44
|
+
eventmachine (>= 1.0.0.beta.4)
|
45
|
+
ethon (0.6.1)
|
46
|
+
ffi (>= 1.3.0)
|
47
|
+
mime-types (~> 1.18)
|
48
|
+
eventmachine (1.0.3)
|
49
|
+
faker (0.9.5)
|
50
|
+
i18n (~> 0.4)
|
51
|
+
fakeredis (0.4.1)
|
52
|
+
redis (~> 3.0.0)
|
53
|
+
faye (0.8.9)
|
54
|
+
cookiejar (>= 0.3.0)
|
55
|
+
em-http-request (>= 0.3.0)
|
56
|
+
eventmachine (>= 0.12.0)
|
57
|
+
faye-websocket (>= 0.4.0)
|
58
|
+
rack (>= 1.0.0)
|
59
|
+
yajl-ruby (>= 1.0.0)
|
60
|
+
faye-websocket (0.7.0)
|
61
|
+
eventmachine (>= 0.12.0)
|
62
|
+
websocket-driver (>= 0.3.0)
|
63
|
+
ffi (1.9.0)
|
64
|
+
growl (1.0.3)
|
65
|
+
guard (1.6.2)
|
66
|
+
listen (>= 0.6.0)
|
67
|
+
lumberjack (>= 1.0.2)
|
68
|
+
pry (>= 0.9.10)
|
69
|
+
terminal-table (>= 1.4.3)
|
70
|
+
thor (>= 0.14.6)
|
71
|
+
guard-bundler (1.0.0)
|
72
|
+
bundler (~> 1.0)
|
73
|
+
guard (~> 1.1)
|
74
|
+
guard-rspec (2.4.1)
|
75
|
+
guard (>= 1.1)
|
76
|
+
rspec (~> 2.11)
|
77
|
+
http_parser.rb (0.6.0.beta.2)
|
78
|
+
i18n (0.6.1)
|
79
|
+
listen (0.7.3)
|
80
|
+
lumberjack (1.0.2)
|
81
|
+
machinist (1.0.6)
|
82
|
+
method_source (0.8.1)
|
83
|
+
mime-types (1.25)
|
84
|
+
multi_json (1.8.0)
|
85
|
+
polyamorous (0.6.4)
|
86
|
+
activerecord (>= 3.0)
|
87
|
+
pry (0.9.12)
|
88
|
+
coderay (~> 1.0.5)
|
89
|
+
method_source (~> 0.8)
|
90
|
+
slop (~> 3.4)
|
91
|
+
rack (1.5.2)
|
92
|
+
rack-protection (1.5.0)
|
93
|
+
rack
|
94
|
+
rack-test (0.6.2)
|
95
|
+
rack (>= 1.0)
|
96
|
+
rake (10.0.3)
|
97
|
+
rb-fsevent (0.9.3)
|
98
|
+
redis (3.0.2)
|
99
|
+
redis-namespace (1.3.1)
|
100
|
+
redis (~> 3.0.0)
|
101
|
+
rspec (2.13.0)
|
102
|
+
rspec-core (~> 2.13.0)
|
103
|
+
rspec-expectations (~> 2.13.0)
|
104
|
+
rspec-mocks (~> 2.13.0)
|
105
|
+
rspec-core (2.13.0)
|
106
|
+
rspec-expectations (2.13.0)
|
107
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
108
|
+
rspec-mocks (2.13.0)
|
109
|
+
sinatra (1.4.3)
|
110
|
+
rack (~> 1.4)
|
111
|
+
rack-protection (~> 1.4)
|
112
|
+
tilt (~> 1.3, >= 1.3.4)
|
113
|
+
slop (3.4.3)
|
114
|
+
sqlite3 (1.3.7)
|
115
|
+
squeel (1.1.1)
|
116
|
+
activerecord (>= 3.0)
|
117
|
+
activesupport (>= 3.0)
|
118
|
+
polyamorous (~> 0.6.0)
|
119
|
+
terminal-table (1.4.5)
|
120
|
+
thor (0.17.0)
|
121
|
+
tilt (1.4.1)
|
122
|
+
typhoeus (0.6.5)
|
123
|
+
ethon (~> 0.6.1)
|
124
|
+
tzinfo (0.3.37)
|
125
|
+
virtus (0.5.5)
|
126
|
+
backports (~> 3.3)
|
127
|
+
descendants_tracker (~> 0.0.1)
|
128
|
+
websocket-driver (0.3.0)
|
129
|
+
yajl-ruby (1.1.0)
|
130
|
+
|
131
|
+
PLATFORMS
|
132
|
+
ruby
|
133
|
+
|
134
|
+
DEPENDENCIES
|
135
|
+
faker (~> 0.9.5)
|
136
|
+
fakeredis
|
137
|
+
growl
|
138
|
+
guard
|
139
|
+
guard-bundler
|
140
|
+
guard-rspec
|
141
|
+
machinist (~> 1.0.6)
|
142
|
+
rack-test
|
143
|
+
rake
|
144
|
+
rb-fsevent
|
145
|
+
rspec
|
146
|
+
smooth!
|
147
|
+
sqlite3 (~> 1.3.3)
|
data/Guardfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
MIT Copyright (c) 2010-2013 Jonathan Soeder
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Smooth.io
|
2
|
+
[![Build Status](https://travis-ci.org/datapimp/smooth.png?branch=master)](https://travis-ci.org/datapimp/smooth)
|
3
|
+
|
4
|
+
### Syncable Cross Platform Persistence
|
5
|
+
|
6
|
+
Smooth.io is provides a free JSON API out of the box, with a declarative syntax
|
7
|
+
to control who can query the API, and what they are able to see.
|
8
|
+
|
9
|
+
Smooth resources expose configuration data in their API endpoints that
|
10
|
+
allow for API clients to discover reource, configure themselves to the data schema.
|
11
|
+
|
12
|
+
Smooth resources have automatic caching with smart expiration, and built in HTTP cache control.
|
13
|
+
|
14
|
+
- Swappable Storage Backends
|
15
|
+
- [ ] Redis Backend
|
16
|
+
- [ ] File Backend
|
17
|
+
- [ ] ActiveRecord Backend
|
18
|
+
|
19
|
+
- Query Interfaces
|
20
|
+
- [ ] Squeel
|
21
|
+
- [ ] Backbone-Query
|
22
|
+
|
23
|
+
- REST Interfaces
|
24
|
+
- [ ] Rails Controller
|
25
|
+
- [ ] Restful Sinatra App
|
26
|
+
- [ ] Faye Pub/Sub fo Auto-Syncing
|
27
|
+
|
28
|
+
- Clients / Syncing
|
29
|
+
- [ ] Ruby
|
30
|
+
- [ ] Coffeescript
|
31
|
+
- [ ] iOS
|
32
|
+
- [ ] Android
|
33
|
+
|
data/Rakefile
ADDED
data/bin/smooth
ADDED
data/doc/presenters.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
## Presenters
|
2
|
+
|
3
|
+
Smooth::Resource classes expose an API for querying data, presenting it
|
4
|
+
it as a desired view, and customizing that presentation for the role of
|
5
|
+
the user querying the API.
|
6
|
+
|
7
|
+
Given the following model configuration:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class Person < ActiveRecord::Base
|
11
|
+
include Smooth::Resource
|
12
|
+
end
|
13
|
+
|
14
|
+
class PersonPresenter
|
15
|
+
def self.default
|
16
|
+
[:name, :public_profile_attributes]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.admin_default
|
20
|
+
default + [:coolness_rating, :black_listed?]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
25
|
+
We will eventually query this resource through the Smooth::Presentable::Controller
|
26
|
+
and will end up making our call to the Query API via the following
|
27
|
+
chain:
|
28
|
+
|
29
|
+
If we are an admin:
|
30
|
+
|
31
|
+
```
|
32
|
+
# uses the admin_default presenter
|
33
|
+
Person.present(query).as(:default).to(:admin)
|
34
|
+
```
|
35
|
+
|
36
|
+
If we are something else, that is not defined, it defaults:
|
37
|
+
|
38
|
+
```
|
39
|
+
# uses the default presenter
|
40
|
+
Person.present(query).as(:default).to(:something_else)
|
41
|
+
```
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
data/lib/smooth.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
require 'active_record'
|
3
|
+
require 'typhoeus'
|
4
|
+
require 'redis'
|
5
|
+
require 'redis-namespace'
|
6
|
+
require 'squeel'
|
7
|
+
require 'virtus'
|
8
|
+
|
9
|
+
module Smooth
|
10
|
+
mattr_accessor :data_directory, :namespace
|
11
|
+
|
12
|
+
def self.namespace
|
13
|
+
@@namespace || "smooth"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.project
|
17
|
+
if defined?(::Rails)
|
18
|
+
Rails.application.class.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.environment
|
23
|
+
ENV['RAILS_ENV'] || ENV['SMOOTH_ENV'] || "development"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.data_directory
|
27
|
+
@@data_directory || File.join(ENV['HOME'],'.smooth',environment)
|
28
|
+
end
|
29
|
+
|
30
|
+
require 'smooth/version'
|
31
|
+
require 'smooth/meta_data'
|
32
|
+
require 'smooth/meta_data/application'
|
33
|
+
|
34
|
+
require 'smooth/queryable'
|
35
|
+
|
36
|
+
require 'smooth/presentable/chain'
|
37
|
+
require 'smooth/presentable/controller'
|
38
|
+
require 'smooth/presentable/api_endpoint'
|
39
|
+
require 'smooth/presentable'
|
40
|
+
|
41
|
+
require 'smooth/backends/base'
|
42
|
+
require 'smooth/backends/active_record'
|
43
|
+
require 'smooth/backends/file'
|
44
|
+
require 'smooth/backends/redis'
|
45
|
+
require 'smooth/backends/redis_namespace'
|
46
|
+
require 'smooth/backends/rest_client'
|
47
|
+
|
48
|
+
require 'smooth/adapters/redis_cache.rb'
|
49
|
+
|
50
|
+
require 'smooth/model'
|
51
|
+
require 'smooth/collection/cacheable'
|
52
|
+
require 'smooth/collection/query'
|
53
|
+
|
54
|
+
require 'smooth/collection'
|
55
|
+
require "smooth/resource"
|
56
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Smooth
|
2
|
+
module Adapters
|
3
|
+
class RailsCache
|
4
|
+
|
5
|
+
def get key
|
6
|
+
Rails.cache.get(key)
|
7
|
+
end
|
8
|
+
|
9
|
+
def write key, value
|
10
|
+
Rails.cache.write(key, value)
|
11
|
+
value
|
12
|
+
end
|
13
|
+
|
14
|
+
def fetch key, &block
|
15
|
+
Rails.cache.fetch key, &block
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Smooth
|
2
|
+
module Adapters
|
3
|
+
class RedisCache
|
4
|
+
attr_accessor :redis
|
5
|
+
|
6
|
+
def initialize redis, options={}
|
7
|
+
if redis.is_a?(Hash)
|
8
|
+
options = redis
|
9
|
+
redis = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
@redis = redis || Redis.new(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def get key
|
16
|
+
redis.get(key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def write key, value
|
20
|
+
redis.set(key, value)
|
21
|
+
value
|
22
|
+
end
|
23
|
+
|
24
|
+
def fetch key
|
25
|
+
result = get(key)
|
26
|
+
|
27
|
+
if result.nil? and block_given?
|
28
|
+
fallback = yield
|
29
|
+
result = write(key, fallback)
|
30
|
+
end
|
31
|
+
|
32
|
+
result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Smooth
|
2
|
+
module Backends
|
3
|
+
class ActiveRecord < Base
|
4
|
+
|
5
|
+
attr_accessor :model
|
6
|
+
|
7
|
+
def initialize options={}
|
8
|
+
super
|
9
|
+
if @model = options[:model]
|
10
|
+
model.send(:include, Smooth::Backends::ActiveRecord::QueryAdapter)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def query params={}
|
15
|
+
model.respond_to?(:query) ? model.query(params) : model.smooth_query(params)
|
16
|
+
end
|
17
|
+
|
18
|
+
def index
|
19
|
+
model.scoped
|
20
|
+
end
|
21
|
+
|
22
|
+
def show id
|
23
|
+
model.find(id)
|
24
|
+
end
|
25
|
+
|
26
|
+
def update attributes
|
27
|
+
record = model.find(attributes[:id])
|
28
|
+
record.update_attributes(attributes)
|
29
|
+
record
|
30
|
+
end
|
31
|
+
|
32
|
+
def destroy id
|
33
|
+
!!(model = model.find(id) && model.destroy)
|
34
|
+
end
|
35
|
+
|
36
|
+
def create attributes
|
37
|
+
record = model.create(attributes)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module ActiveRecord::QueryAdapter
|
42
|
+
|
43
|
+
module ClassMethods
|
44
|
+
def smooth_query params={}
|
45
|
+
scoped
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.included(receiver)
|
50
|
+
receiver.extend ClassMethods
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|