tupplur 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f2b8e48210120a1b238121391fc8552891670c81
4
+ data.tar.gz: 494017fd71c91f6fd6c936200df729a7adb201cd
5
+ SHA512:
6
+ metadata.gz: bf38291747032151dc4cf271d31b2fc560f123dc71b3b494006fb02d9a7fb3ff663b7d447a926ef4dddd9d9129dbdfc7f4f18b03c9d2d8735f11fdfd52dbd191
7
+ data.tar.gz: ed1ca103911a472313dfb7725c1dd54dc6d55165006a9ba3c71385b0b94051a05362d7eaacd471207ad37174d40fbe9ae1b86f0f81850ed66a0badb0b90b5a5f
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tupplur.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Robin Edman
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,115 @@
1
+ # Tupplur
2
+
3
+ Tupplur extends your Mongoid 3.x models, allowing you to expose fields as readable
4
+ or writable from outside of your application. It includes a Rack REST adapter,
5
+ so that any Rack app can expose some or all of its' models as JSON easily
6
+ through a standard REST CRUD api.
7
+
8
+ This library is especially useful if you're building APIs for mobile or
9
+ Single Page Applications (maybe using Backbone, Spine, AngularJS or whichever
10
+ framework you prefer).
11
+
12
+ It's been designed to work well straight on top of Rack, or with lightweight
13
+ Rack-based frameworks such as Sinatra and Cuba. In fact, the REST adapter is
14
+ implemented as a Cuba application.
15
+
16
+ If you're using Rails you're probably better off with another solution at the
17
+ moment, since it might make more sense to use something that's more
18
+ integrated into the framework.
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ gem 'tupplur'
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install tupplur
33
+
34
+ If necessary in your application:
35
+ ```
36
+ require 'tupplur' # at the appropriate place.
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ Tupplur is divided into two parts: a model mixin and a Rack
42
+ application which acts like a REST endpoint.
43
+
44
+ ### REST endpoint Rack application
45
+ After Mongoid has been set up, mount the Rack app on a route of your choice.
46
+ The details of how you do this will depend on which framework you're using.
47
+ Each model gets its' own endpoint. So repeat this for all
48
+ models for which you want to provide a REST interface.
49
+
50
+ In Cuba:
51
+ ```ruby
52
+ on "/users" do
53
+ run Tupplur::RESTEndpoint.new(User)
54
+ end
55
+ ```
56
+
57
+ In Rack (in config.ru):
58
+ ```ruby
59
+ run Rack::URLMap.new("/" => YourApp.new,
60
+ "/users" => Tupplur::RESTEndpoint.new(User))
61
+ ```
62
+
63
+ If you're using Sinatra you might prefer the Rack method to mounting it
64
+ within Sinatra itself.
65
+
66
+ ### Model mixin
67
+ In your model:
68
+ ```ruby
69
+ class User
70
+ include Mongoid::Document
71
+ include Tupplur::ModelExtensions
72
+
73
+ # Define which operations you want to support.
74
+ rest_interface :create,
75
+ :read,
76
+ :update,
77
+ :delete
78
+
79
+ # Fields that are to be both readable and writable.
80
+ externally_accessible :name,
81
+ :email
82
+
83
+ # Read-only fields.
84
+ externally_readable :active
85
+
86
+ # Put your regular Mongoid model code here (or anywhere you want to as the ordering doesn't matter.)
87
+ field :name, type: String
88
+ field :email, type: String
89
+ field :password, type: String
90
+ field :active, type: Boolean, default: false
91
+ end
92
+ ```
93
+ This is where you define what parts of your model you want to
94
+ expose outside of your backend application. This is configured
95
+ in a similar manner to the way we choose to expose attributes on
96
+ objects in plain Ruby. There we use atr_reader and
97
+ attr_accessor. Tupplur includes the corresponding methods
98
+ externally_readable and externally_accessible.
99
+
100
+ You also define what REST operations a given model should
101
+ support using the rest_interface method. Just like externally_readable and
102
+ externally_writable it takes one or more symbols as arguments: :create, :read,
103
+ :update, :delete. The default is to not support any operation. You may
104
+ see this as whitelisting operations.
105
+
106
+ ### Examples
107
+ In the test directory you'll find an example app which uses the Cuba framework.
108
+
109
+ ## Contributing
110
+
111
+ 1. Fork it
112
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
113
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
114
+ 4. Push to the branch (`git push origin my-new-feature`)
115
+ 5. Create new Pull Request
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+ require "bundler/gem_tasks"
4
+
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.pattern = "test/*_test.rb"
8
+ end
@@ -0,0 +1,8 @@
1
+ require "tupplur/version"
2
+
3
+ require "tupplur/errors"
4
+ require "tupplur/model_extensions"
5
+ require "tupplur/rest_endpoint"
6
+
7
+ module Tupplur
8
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ module Tupplur
4
+ module Error
5
+ class RESTOperationNotAllowed < StandardError
6
+ def message
7
+ "The #{@operation} REST operation is not allowed."
8
+ end
9
+
10
+ def initialize(operation = 'unspecified')
11
+ @operation = operation
12
+ end
13
+ end
14
+
15
+ def self.log_exception(e)
16
+ puts "Exception: #{e}"
17
+ puts "Message: #{e.message}"
18
+ puts e.backtrace.join("\n")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,142 @@
1
+ # encoding: utf-8
2
+
3
+ require "active_support/all"
4
+
5
+ module Tupplur
6
+ module ModelExtensions
7
+ def self.included(base)
8
+ base.const_set(:EXTERNALLY_READABLE_FIELDS, ['_id'])
9
+ base.const_set(:EXTERNALLY_ACCESSIBLE_FIELDS, [])
10
+ base.const_set(:REST_INTERFACE, [])
11
+
12
+ base.send(:include, InstanceMethods)
13
+ base.send(:extend, ClassMethods)
14
+ end
15
+
16
+ module InstanceMethods
17
+ def as_external_document
18
+ doc = self.as_document
19
+
20
+ # note: id fix for client side libraries like Spine.js,
21
+ # who rely on an id attribute being present.
22
+ doc['id'] = doc['_id']
23
+
24
+ doc.slice(*readable_fields + ['id'])
25
+ end
26
+
27
+ def external_update!(document_as_hash)
28
+ allowed_fields = filter_accessible_fields(document_as_hash)
29
+ update_attributes!(allowed_fields)
30
+ end
31
+
32
+ # Does the model allow a certain REST operation?
33
+ # If no operation given: Does the model allow any REST operation at all?
34
+ def rest?(operation)
35
+ if operation
36
+ self.class.const_get(:REST_INTERFACE).include?(operation)
37
+ else
38
+ ! self.class.const_get(:REST_INTERFACE).empty?
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def filter_accessible_fields(hsh)
45
+ hsh.slice(*self.class.const_get(:EXTERNALLY_ACCESSIBLE_FIELDS).map(&:to_s))
46
+ end
47
+
48
+ def readable_fields
49
+ (self.class.const_get(:EXTERNALLY_ACCESSIBLE_FIELDS) + self.class.const_get(:EXTERNALLY_READABLE_FIELDS)).map(&:to_s)
50
+ end
51
+ end
52
+
53
+ module ClassMethods
54
+ # Does the model allow a certain REST operation?
55
+ # If no operation given: Does the model allow any REST operation at all?
56
+ def rest?(operation = nil)
57
+ if operation
58
+ const_get(:REST_INTERFACE).include?(operation)
59
+ else
60
+ ! const_get(:REST_INTERFACE).empty?
61
+ end
62
+ end
63
+
64
+ def rest_read(document_id = nil)
65
+ if document_id
66
+ rest_read_document(document_id)
67
+ else
68
+ rest_read_all
69
+ end
70
+ end
71
+
72
+ def rest_update(document_id, client_model)
73
+ raise Tupplur::Error::RESTOperationNotAllowed.new('update') unless rest?(:update)
74
+
75
+ find(document_id).external_update!(client_model)
76
+ end
77
+
78
+ def rest_delete(document_id)
79
+ raise Tupplur::Error::RESTOperationNotAllowed.new('delete') unless rest?(:delete)
80
+
81
+ find(document_id).delete
82
+ end
83
+
84
+ def rest_create(client_fields)
85
+ raise Tupplur::Error::RESTOperationNotAllowed.new('create') unless rest?(:create)
86
+
87
+ external_create!(client_fields)
88
+ end
89
+
90
+ def rest_read_document(document_id)
91
+ raise Tupplur::Error::RESTOperationNotAllowed.new('read') unless rest?(:read)
92
+
93
+ find(document_id).as_external_document
94
+ end
95
+
96
+ def rest_read_all
97
+ raise Tupplur::Error::RESTOperationNotAllowed.new('read') unless rest?(:read)
98
+
99
+ all.map { |m| m.as_external_document }
100
+ end
101
+
102
+ def external_create!(fields)
103
+ allowed_fields = filter_accessible_fields(fields)
104
+ create!(allowed_fields)
105
+ end
106
+
107
+ private
108
+
109
+ # Externally accessible fields and embedded documents.
110
+ def externally_accessible(*fields)
111
+ const_get(:EXTERNALLY_ACCESSIBLE_FIELDS).push(*fields)
112
+ end
113
+
114
+ # Externally readable fields and embedded documents.
115
+ def externally_readable(*fields)
116
+ const_get(:EXTERNALLY_READABLE_FIELDS).push(*fields)
117
+ end
118
+
119
+ # Used to define allowed REST operations (e.g. :read, :create, :update, :delete).
120
+ # Example usage:
121
+ # class MyModel
122
+ # include Mongoid::Document
123
+ # include Tupplur::ModelExtensions
124
+ #
125
+ # rest_interface :read, :update, :delete
126
+ #
127
+ def rest_interface(*operations)
128
+ const_get(:REST_INTERFACE).push(*operations)
129
+ end
130
+
131
+
132
+ def filter_accessible_fields(hsh)
133
+ hsh.slice(*const_get(:EXTERNALLY_ACCESSIBLE_FIELDS).map(&:to_s))
134
+ end
135
+
136
+ def readable_fields
137
+ (const_get(:EXTERNALLY_ACCESSIBLE_FIELDS) + const_get(:EXTERNALLY_READABLE_FIELDS)).map(&:to_s)
138
+ end
139
+
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+
3
+ require 'cuba'
4
+
5
+ module Tupplur
6
+ class RESTEndpoint < Cuba
7
+ attr_reader :model
8
+
9
+ def initialize(model)
10
+ @model = model
11
+ super() do
12
+ on ":id" do |document_id|
13
+ # REST read document
14
+ on get do
15
+ begin
16
+ send_json(@model.rest_read(document_id))
17
+ rescue Tupplur::Error::RESTOperationNotAllowed => e
18
+ res.status = 401
19
+ end
20
+ end
21
+
22
+ # REST update document
23
+ on put, param('data') do |client_model|
24
+ begin
25
+ send_json(@model.rest_update(document_id, client_model))
26
+ rescue Tupplur::Error::RESTOperationNotAllowed => e
27
+ res.status = 401
28
+ end
29
+ end
30
+
31
+ # REST delete document
32
+ on delete do
33
+ begin
34
+ send_json(@model.rest_delete(document_id))
35
+ rescue Tupplur::Error::RESTOperationNotAllowed => e
36
+ res.status = 401
37
+ end
38
+ end
39
+ end
40
+
41
+ # REST read whole collection
42
+ on get do
43
+ begin
44
+ send_json(@model.rest_read)
45
+ rescue Tupplur::Error::RESTOperationNotAllowed => e
46
+ res.status = 401
47
+ end
48
+ end
49
+
50
+ # REST create document
51
+ on post, param('data') do |client_fields|
52
+ begin
53
+ @model.rest_create(client_fields)
54
+ rescue Tupplur::Error::RESTOperationNotAllowed => e
55
+ res.status = 401
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ def self.define
62
+ raise NotImplementedError, "Use .new and run the app instead."
63
+ end
64
+
65
+ private
66
+
67
+ def send_json(document)
68
+ res['Content-Type'] = 'application/json; charset=utf-8'
69
+ res.write(document.to_json)
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,3 @@
1
+ module Tupplur
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,126 @@
1
+ require_relative "test_helper"
2
+ require_relative "../lib/tupplur"
3
+
4
+ module RESTEndPointTest
5
+ class Base < TupplurTestCase
6
+ def tabula_rasa
7
+ User.delete_all
8
+ Secret.delete_all
9
+ end
10
+
11
+ def setup
12
+ tabula_rasa
13
+
14
+ User.create!(name: "Adam",
15
+ email: "adam@example.com",
16
+ password: "verysecurepassword")
17
+ User.create!(name: "Brenda",
18
+ email: "brenda@example.com",
19
+ password: "verysecurepassword")
20
+
21
+ Secret.create!(message: "Super secret info.")
22
+ end
23
+
24
+ def teardown
25
+ tabula_rasa
26
+ end
27
+ end
28
+
29
+ class GetTest < Base
30
+ test "get all documents returns only readable and accessible attributes" do
31
+ get "/users"
32
+
33
+ expected_response = [{name: "Adam", email: "adam@example.com", active: false},
34
+ {name: "Brenda", email: "brenda@example.com", active: false}]
35
+ response = ActiveSupport::JSON.decode(last_response.body).map(&:symbolize_keys!)
36
+
37
+ assert_equal(expected_response, response.map { |m| m.except(:_id, :id) })
38
+ end
39
+
40
+ test "get document with id returns only readable and accessible attributes" do
41
+ brenda_id = User.find_by(name: "Brenda")._id
42
+ get "/users/#{brenda_id}"
43
+
44
+ expected_response = {name: "Brenda", email: "brenda@example.com", active: false}
45
+ response = ActiveSupport::JSON.decode(last_response.body).symbolize_keys!
46
+
47
+ assert_equal(expected_response, response.except(:_id, :id))
48
+ end
49
+
50
+ test "cannot get resource that does not allow it" do
51
+ get "/secrets"
52
+
53
+ assert_equal(401, last_response.status)
54
+ end
55
+ end
56
+
57
+ class UpdateTest < Base
58
+ test "update accessible attribute" do
59
+ user = User.find_by(name: "Brenda")
60
+ put "/users/#{user._id}", {data: {name: "Brian"}}
61
+ user.reload
62
+
63
+ assert_equal("Brian", user.name)
64
+ end
65
+
66
+ test "cannot update readonly attribute" do
67
+ user = User.last
68
+ put "/users/#{user._id}", {data: {active: true}}
69
+ user.reload
70
+
71
+ refute(user.active)
72
+ end
73
+
74
+ test "cannot update internal attribute" do
75
+ user = User.last
76
+ put "users/#{user._id}", {data: {password: "anotherpassword"}}
77
+ user.reload
78
+
79
+ assert_equal("verysecurepassword", user.password)
80
+ end
81
+
82
+ test "cannot update resource that does not allow it" do
83
+ secret = Secret.first
84
+ put "secrets/#{secret._id}", {data: {message: "I say"}}
85
+ secret.reload
86
+
87
+ assert_equal("Super secret info.", secret.message)
88
+ end
89
+ end
90
+
91
+ class DeleteTest < Base
92
+ test "delete resource" do
93
+ user_id = User.first._id
94
+ delete "/users/#{user_id}"
95
+
96
+ refute(User.find(user_id))
97
+ end
98
+
99
+ test "cannot delete resource that does not allow it" do
100
+ secret_id = Secret.first._id
101
+ delete "/secrets/#{secret_id}"
102
+
103
+ assert(Secret.find(secret_id))
104
+ end
105
+ end
106
+
107
+ class CreateTest < Base
108
+ test "create resource" do
109
+ post "/users", {data: {name: "Charles", email: "charles@example.com"}}
110
+
111
+ assert(User.find_by(name: "Charles"))
112
+ end
113
+
114
+ test "cannot set readable attributes" do
115
+ post "/users", {data: {name: "Roger", active: true}}
116
+
117
+ refute(User.find_by(name: "Roger").active)
118
+ end
119
+
120
+ test "cannot create resource that does not allow it" do
121
+ post "/secrets", {data: {message: "Hey"}}
122
+
123
+ refute(Secret.find_by(message: "Hey"))
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,20 @@
1
+ require "mongoid"
2
+ require_relative "helpers"
3
+
4
+ cd_to_here
5
+ Mongoid.load!("./mongoid.yml")
6
+
7
+ require_relative "../../lib/tupplur"
8
+ require_relative "models/user"
9
+ require_relative "models/secret"
10
+
11
+ Cuba.define do
12
+ on "users" do
13
+ run Tupplur::RESTEndpoint.new(User)
14
+ end
15
+
16
+ on "secrets" do
17
+ run Tupplur::RESTEndpoint.new(Secret)
18
+ end
19
+ end
20
+
@@ -0,0 +1,4 @@
1
+ #encoding: utf-8
2
+ require './app'
3
+
4
+ run Cuba
@@ -0,0 +1,4 @@
1
+ def cd_to_here
2
+ root_directory = File.expand_path(File.dirname(__FILE__))
3
+ Dir.chdir(root_directory)
4
+ end
@@ -0,0 +1,7 @@
1
+ class Secret
2
+ include Mongoid::Document
3
+ include Tupplur::ModelExtensions
4
+
5
+ field :message, type: String
6
+ end
7
+
@@ -0,0 +1,20 @@
1
+ class User
2
+ include Mongoid::Document
3
+ include Tupplur::ModelExtensions
4
+
5
+ rest_interface :create,
6
+ :read,
7
+ :update,
8
+ :delete
9
+
10
+ externally_accessible :name,
11
+ :email
12
+
13
+ externally_readable :active
14
+
15
+ field :name, type: String
16
+ field :email, type: String
17
+ field :password, type: String
18
+ field :active, type: Boolean, default: false
19
+ end
20
+
@@ -0,0 +1,20 @@
1
+ # Tell Mongoid which environment this configuration is for.
2
+ development:
3
+ # This starts the session configuration settings. You may have as
4
+ # many sessions as you like, but you must have at least 1 named
5
+ # 'default'.
6
+ sessions:
7
+ # Define the default session.
8
+ default:
9
+ # A session can have any number of hosts. Usually 1 for a single
10
+ # server setup, and at least 3 for a replica set. Hosts must be
11
+ # an array of host:port pairs. This session is single server.
12
+ hosts:
13
+ - 127.0.0.1:27017
14
+ # Define the default database name.
15
+ database: tupplurtest
16
+ # Set username and password if you need to.
17
+ # username: user
18
+ # password: password
19
+ options:
20
+ raise_not_found_error: false
@@ -0,0 +1,14 @@
1
+ require "turn/autorun"
2
+ require "active_support/all"
3
+ require "rack/test"
4
+ require_relative "test_app/app"
5
+
6
+ Turn.config.natural = true
7
+
8
+ class TupplurTestCase < ActiveSupport::TestCase
9
+ include Rack::Test::Methods
10
+
11
+ def app
12
+ Cuba
13
+ end
14
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ #lib = File.expand_path('../lib', __FILE__)
3
+ #$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ # require 'tupplur/version'
5
+ require File.expand_path('../lib/tupplur/version', __FILE__)
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "tupplur"
9
+ spec.version = Tupplur::VERSION
10
+ spec.authors = ["Robin Edman"]
11
+ spec.email = ["robin.edman@gmail.com"]
12
+ spec.description = %q{Tupplur extends Mongoid, allowing fields to be exposed as readable or writable from outside of your application.}
13
+ spec.summary = spec.description
14
+ spec.homepage = ""
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "turn", "~> 0.9"
25
+ spec.add_development_dependency "activesupport", "~> 3.0"
26
+ spec.add_development_dependency "rack-test", "~> 0.6.2"
27
+ spec.add_development_dependency "virtus", "~> 1.0"
28
+ spec.add_development_dependency "mongoid", "~> 3.0"
29
+
30
+ spec.add_runtime_dependency "cuba", "~>3.1.0"
31
+ # Mongoid is an implicitly assumed dependency. So is ActiveSupport.
32
+ # We don't specify those versions since we don't want to risk conflicts with
33
+ # Mongoid.
34
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tupplur
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Robin Edman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: turn
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack-test
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 0.6.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 0.6.2
83
+ - !ruby/object:Gem::Dependency
84
+ name: virtus
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '1.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: mongoid
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '3.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '3.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: cuba
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 3.1.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: 3.1.0
125
+ description: Tupplur extends Mongoid, allowing fields to be exposed as readable or
126
+ writable from outside of your application.
127
+ email:
128
+ - robin.edman@gmail.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - .gitignore
134
+ - Gemfile
135
+ - LICENSE.txt
136
+ - README.md
137
+ - Rakefile
138
+ - lib/tupplur.rb
139
+ - lib/tupplur/errors.rb
140
+ - lib/tupplur/model_extensions.rb
141
+ - lib/tupplur/rest_endpoint.rb
142
+ - lib/tupplur/version.rb
143
+ - test/rest_endpoint_test.rb
144
+ - test/test_app/app.rb
145
+ - test/test_app/config.ru
146
+ - test/test_app/helpers.rb
147
+ - test/test_app/models/secret.rb
148
+ - test/test_app/models/user.rb
149
+ - test/test_app/mongoid.yml
150
+ - test/test_helper.rb
151
+ - tupplur.gemspec
152
+ homepage: ''
153
+ licenses:
154
+ - MIT
155
+ metadata: {}
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - '>='
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - '>='
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubyforge_project:
172
+ rubygems_version: 2.0.3
173
+ signing_key:
174
+ specification_version: 4
175
+ summary: Tupplur extends Mongoid, allowing fields to be exposed as readable or writable
176
+ from outside of your application.
177
+ test_files:
178
+ - test/rest_endpoint_test.rb
179
+ - test/test_app/app.rb
180
+ - test/test_app/config.ru
181
+ - test/test_app/helpers.rb
182
+ - test/test_app/models/secret.rb
183
+ - test/test_app/models/user.rb
184
+ - test/test_app/mongoid.yml
185
+ - test/test_helper.rb