restpack-resource 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/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ *.db
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.3"
4
+ script: bundle exec rake test
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :test do
4
+ gem 'rake', '~> 10.0.3'
5
+ gem 'rspec', :require => 'spec'
6
+ gem 'datamapper', '~> 1.2.0'
7
+ gem 'dm-pager', '~> 1.1.0'
8
+ gem 'dm-sqlite-adapter', '~> 1.2.0'
9
+ gem 'factory_girl', '~> 4.2.0'
10
+ end
11
+
12
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,95 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ restpack-resource (0.0.1)
5
+ active_support (~> 3.0.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ active_support (3.0.0)
11
+ activesupport (= 3.0.0)
12
+ activesupport (3.0.0)
13
+ addressable (2.2.8)
14
+ bcrypt-ruby (3.0.1)
15
+ data_objects (0.10.12)
16
+ addressable (~> 2.1)
17
+ datamapper (1.2.0)
18
+ dm-aggregates (~> 1.2.0)
19
+ dm-constraints (~> 1.2.0)
20
+ dm-core (~> 1.2.0)
21
+ dm-migrations (~> 1.2.0)
22
+ dm-serializer (~> 1.2.0)
23
+ dm-timestamps (~> 1.2.0)
24
+ dm-transactions (~> 1.2.0)
25
+ dm-types (~> 1.2.0)
26
+ dm-validations (~> 1.2.0)
27
+ diff-lcs (1.1.3)
28
+ dm-aggregates (1.2.0)
29
+ dm-core (~> 1.2.0)
30
+ dm-constraints (1.2.0)
31
+ dm-core (~> 1.2.0)
32
+ dm-core (1.2.0)
33
+ addressable (~> 2.2.6)
34
+ dm-do-adapter (1.2.0)
35
+ data_objects (~> 0.10.6)
36
+ dm-core (~> 1.2.0)
37
+ dm-migrations (1.2.0)
38
+ dm-core (~> 1.2.0)
39
+ dm-pager (1.1.0)
40
+ dm-aggregates (>= 0.10.1)
41
+ dm-core (>= 0.10.1)
42
+ dm-serializer (1.2.2)
43
+ dm-core (~> 1.2.0)
44
+ fastercsv (~> 1.5)
45
+ json (~> 1.6)
46
+ json_pure (~> 1.6)
47
+ multi_json (~> 1.0)
48
+ dm-sqlite-adapter (1.2.0)
49
+ dm-do-adapter (~> 1.2.0)
50
+ do_sqlite3 (~> 0.10.6)
51
+ dm-timestamps (1.2.0)
52
+ dm-core (~> 1.2.0)
53
+ dm-transactions (1.2.0)
54
+ dm-core (~> 1.2.0)
55
+ dm-types (1.2.2)
56
+ bcrypt-ruby (~> 3.0)
57
+ dm-core (~> 1.2.0)
58
+ fastercsv (~> 1.5)
59
+ json (~> 1.6)
60
+ multi_json (~> 1.0)
61
+ stringex (~> 1.4)
62
+ uuidtools (~> 2.1)
63
+ dm-validations (1.2.0)
64
+ dm-core (~> 1.2.0)
65
+ do_sqlite3 (0.10.12)
66
+ data_objects (= 0.10.12)
67
+ factory_girl (4.2.0)
68
+ activesupport (>= 3.0.0)
69
+ fastercsv (1.5.5)
70
+ json (1.7.6)
71
+ json_pure (1.7.6)
72
+ multi_json (1.5.0)
73
+ rake (10.0.3)
74
+ rspec (2.12.0)
75
+ rspec-core (~> 2.12.0)
76
+ rspec-expectations (~> 2.12.0)
77
+ rspec-mocks (~> 2.12.0)
78
+ rspec-core (2.12.2)
79
+ rspec-expectations (2.12.1)
80
+ diff-lcs (~> 1.1.3)
81
+ rspec-mocks (2.12.2)
82
+ stringex (1.5.1)
83
+ uuidtools (2.1.3)
84
+
85
+ PLATFORMS
86
+ ruby
87
+
88
+ DEPENDENCIES
89
+ datamapper (~> 1.2.0)
90
+ dm-pager (~> 1.1.0)
91
+ dm-sqlite-adapter (~> 1.2.0)
92
+ factory_girl (~> 4.2.0)
93
+ rake (~> 10.0.3)
94
+ restpack-resource!
95
+ rspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2013 Gavin Joyce and RestPack contributors
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # restpack-resource [![Build Status](https://api.travis-ci.org/RestPack/restpack-resource.png?branch=master)](https://travis-ci.org/RestPack/restpack-resource) [![Code Climate](https://codeclimate.com/github/RESTpack/restpack-resource.png)](https://codeclimate.com/github/RESTpack/restpack-resource) [![Dependency Status](https://gemnasium.com/RestPack/restpack-resource.png)](https://gemnasium.com/RestPack/restpack-resource)
2
+
3
+ RESTful resource paging, side-loading, filtering and sorting:
4
+
5
+ ```ruby
6
+ class Group
7
+ include DataMapper::Resource
8
+ include RestPack::Resource
9
+
10
+ property :id, Serial
11
+ property :name, String, :length => 128
12
+ property :created_by, Integer, :required => true
13
+ property :channel_id, Integer, :required => true
14
+ timestamps :at
15
+
16
+ validates_presence_of :name, :channel_id
17
+
18
+ has n, :invitations
19
+ has n, :memberships
20
+
21
+ resource_can_include :memberships, :invitations
22
+ resource_can_filter_by :channel_id, :created_by
23
+ resource_can_sort_by :id
24
+ end
25
+ ```
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default => :test
4
+ task :test => :spec
5
+
6
+ begin
7
+ require "rspec/core/rake_task"
8
+
9
+ desc "Run all specs"
10
+ RSpec::Core::RakeTask.new(:spec) do |t|
11
+ t.rspec_opts = ['-cfs']
12
+ end
13
+ rescue LoadError
14
+ end
@@ -0,0 +1,22 @@
1
+ require 'active_support/core_ext/hash'
2
+
3
+ module RestPack
4
+ module Resource
5
+ module Filterable
6
+ def resource_filterable_by
7
+ @resource_filterable_by || []
8
+ end
9
+ def resource_filterable_by=(columns)
10
+ @resource_filterable_by = columns
11
+ end
12
+ def resource_can_filter_by(*columns)
13
+ self.resource_filterable_by += columns
14
+ end
15
+ def resource_validate_filters!(filters)
16
+ filters.keys.each do |filter|
17
+ raise InvalidFilter.new unless self.resource_filterable_by.include?(filter)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ require 'active_support/core_ext/hash'
2
+
3
+ module RestPack
4
+ module Resource
5
+ module Includable
6
+ def resource_includable_associations
7
+ @resource_includable_associations || []
8
+ end
9
+ def resource_includable_associations=(associations)
10
+ @resource_includable_associations = associations
11
+ end
12
+ def resource_can_include(*associations)
13
+ self.resource_includable_associations += associations
14
+ end
15
+ def resource_validate_includes!(includes)
16
+ includes.each do |include|
17
+ unless self.resource_includable_associations.include?(include)
18
+ raise InvalidInclude, "#{self.name}.#{include} is not an includable relation"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,114 @@
1
+ require 'active_support/core_ext/hash'
2
+
3
+ module RestPack
4
+ module Resource
5
+ module Pageable
6
+ def paged_resource(params = {}, overrides = {})
7
+ options = build_options(params, overrides)
8
+ get_paged_resource(options)
9
+ end
10
+
11
+ protected
12
+
13
+ def get_paged_resource(options)
14
+ page = get_page(options)
15
+
16
+ paged_resource = {
17
+ :page => page.pager.current_page,
18
+ :page_count => page.pager.total_pages,
19
+ :total => page.pager.total,
20
+ :previous_page => page.pager.previous_page,
21
+ :next_page => page.pager.next_page
22
+ }
23
+
24
+ paged_resource[self.resource_collection_name] = page.map { |item| item.to_resource() }
25
+
26
+ unless page.empty?
27
+ options[:includes].each do |association|
28
+ paged_resource[association] = side_load(page, association)
29
+ end
30
+ end
31
+
32
+ paged_resource
33
+ end
34
+
35
+ def get_page(options)
36
+ order = options[:sort_by]
37
+ order = order.desc if order && options[:sort_direction] == :descending
38
+
39
+ options[:scope].all(:conditions => options[:filters]).page(options[:page], :order => order)
40
+ end
41
+
42
+ def side_load(page, association)
43
+ target_model_name = association.to_s.singularize.capitalize
44
+ relationships = self.relationships.select {|r| r.target_model.to_s == target_model_name }
45
+ raise InvalidInclude if relationships.empty?
46
+
47
+ side_loaded_entities = []
48
+
49
+ relationships.each do |relationship|
50
+ unless relationship.is_a? DataMapper::Associations::ManyToOne::Relationship
51
+ raise InvalidInclude, "#{self.name}.#{relationship.name} can't be included when paging #{self.name.pluralize.downcase}"
52
+ end
53
+ side_loaded_entities += page.map do |entity| #TODO: GJ: PERF: we can bypass datamapper associations and get by a list of ids instead
54
+ relation = entity.send(relationship.name.to_sym)
55
+ relation ? relation.to_resource : nil
56
+ end
57
+ side_loaded_entities.uniq!
58
+ side_loaded_entities.compact!
59
+ end
60
+
61
+ side_loaded_entities
62
+ end
63
+
64
+ def resource_collection_name
65
+ self.name.to_s.downcase.pluralize.to_sym
66
+ end
67
+
68
+ def build_options(params, overrides)
69
+ options = overrides.reverse_merge( #overrides take precedence over params
70
+ :page => params[:page],
71
+ :includes => params[:includes].nil? ? [] : params[:includes].split(','),
72
+ :filters => self.extract_filters_from_params(params),
73
+ :sort_by => params[:sort_by],
74
+ :sort_direction => params[:sort_direction]
75
+ )
76
+
77
+ options.reverse_merge!( #defaults
78
+ :scope => self.all,
79
+ :page => 1,
80
+ :includes => [],
81
+ :filters => {},
82
+ :sort_by => nil,
83
+ :sort_direction => :ascending
84
+ )
85
+
86
+ resource_normalise_options!(options)
87
+ resource_validate_options!(options)
88
+
89
+ options
90
+ end
91
+
92
+ def extract_filters_from_params(params)
93
+ extracted = params.extract!(*self.resource_filterable_by)
94
+ extracted.delete_if { |k, v| v.nil? }
95
+ end
96
+
97
+ private
98
+
99
+ def resource_normalise_options!(options)
100
+ options[:includes].map!{|i| i.to_sym}
101
+
102
+ [:sort_by, :sort_direction].each do |attribute|
103
+ options[attribute] = options[attribute].to_sym if options[attribute]
104
+ end
105
+ end
106
+
107
+ def resource_validate_options!(options)
108
+ self.resource_validate_includes! options[:includes]
109
+ self.resource_validate_filters! options[:filters]
110
+ self.resource_validate_sort_by! options[:sort_by]
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,20 @@
1
+ require 'active_support/core_ext/hash'
2
+
3
+ module RestPack
4
+ module Resource
5
+ module Sortable
6
+ def resource_sortable_by
7
+ @resource_sortable_by || []
8
+ end
9
+ def resource_sortable_by=(columns)
10
+ @resource_sortable_by = columns
11
+ end
12
+ def resource_can_sort_by(*columns)
13
+ self.resource_sortable_by += columns
14
+ end
15
+ def resource_validate_sort_by!(sort_by)
16
+ raise InvalidSortBy.new unless sort_by.nil? || self.resource_sortable_by.include?(sort_by)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ %w{pageable filterable sortable includable}.each {|m| require "restpack-resource/resource/#{m}" }
2
+
3
+ module RestPack
4
+ module Resource
5
+ class InvalidInclude < Exception; end
6
+ class InvalidFilter < Exception; end
7
+ class InvalidSortBy < Exception; end
8
+
9
+ def self.included(base)
10
+ base.extend(ClassMethods)
11
+ base.extend(RestPack::Resource::Pageable)
12
+ base.extend(RestPack::Resource::Filterable)
13
+ base.extend(RestPack::Resource::Sortable)
14
+ base.extend(RestPack::Resource::Includable)
15
+ super
16
+ end
17
+
18
+ def to_resource(options = {})
19
+ self
20
+ end
21
+
22
+ module ClassMethods
23
+ def resource_single_resource(options = {})
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,5 @@
1
+ module RestPack
2
+ module Resource
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ require 'restpack-resource/version'
2
+ require 'restpack-resource/resource'
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'restpack-resource/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "restpack-resource"
8
+ gem.version = RestPack::Resource::VERSION
9
+ gem.authors = ["Gavin Joyce"]
10
+ gem.email = ["gavinjoyce@gmail.com"]
11
+ gem.description = %q{RESTful resource paging, side-loading, filtering and sorting}
12
+ gem.summary = %q{...}
13
+ gem.homepage = "https://github.com/RESTpack/restpack-resource"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'active_support', '~> 3.0.0'
21
+ gem.add_development_dependency 'rspec', '~> 2.12'
22
+ end
data/spec/factories.rb ADDED
@@ -0,0 +1,21 @@
1
+ FactoryGirl.define do
2
+ factory :user do
3
+ sequence(:name) {|n| "User #{n}" }
4
+ end
5
+
6
+ factory :artist do
7
+ sequence(:name) {|n| "Artist #{n}" }
8
+ end
9
+
10
+ factory :song do
11
+ sequence(:name) {|n| "Song #{n}" }
12
+ artist
13
+ association :creator, factory: :user
14
+ association :modifier, factory: :user
15
+ end
16
+
17
+ factory :comment do
18
+ sequence(:test) {|n| "This is comment #{n}" }
19
+ song
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ require './spec/spec_helper'
2
+
3
+ describe RestPack::Resource do
4
+ describe "#paged_resource" do
5
+ context "when filtering" do
6
+ context "with valid options" do
7
+ before(:each) do
8
+ @artist = create(:artist)
9
+ 3.times { create(:song, artist: @artist) }
10
+ 9.times { create(:song) }
11
+ end
12
+
13
+ it "should return the total count" do
14
+ result = Song.paged_resource()
15
+ result[:total].should == 12
16
+ end
17
+
18
+ it "should filter results" do
19
+ result = Song.paged_resource(artist_id: @artist.id)
20
+ result[:total].should == 3
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,90 @@
1
+ require './spec/spec_helper'
2
+
3
+ describe RestPack::Resource do
4
+ describe "#paged_resource" do
5
+ context "when paging" do
6
+ context "with no data" do
7
+ before(:each) do
8
+ Song.destroy
9
+ end
10
+
11
+ it "should return an empty array" do
12
+ result = Song.paged_resource()
13
+ result.should_not == nil
14
+ result[:songs].should_not == nil
15
+ end
16
+ end
17
+
18
+ context "with data" do
19
+ before(:each) do
20
+ 16.times { create(:song) }
21
+ end
22
+
23
+ it "has a valid first page" do
24
+ result = Artist.paged_resource()
25
+ result[:page].should == 1
26
+ result[:total].should == 16
27
+ result[:page_count].should == 2
28
+ result[:previous_page].should == nil
29
+ result[:next_page].should == 2
30
+ result[:artists].size.should == 10
31
+ end
32
+
33
+ it "has a valid second page" do
34
+ result = Artist.paged_resource(page: 2)
35
+ result[:page].should == 2
36
+ result[:previous_page].should == 1
37
+ result[:next_page].should == nil
38
+ result[:artists].size.should == 6
39
+ end
40
+
41
+ context "when including relations" do
42
+ it "should not allow invalid relations" do
43
+ expect do
44
+ Artist.paged_resource(:includes => 'invalid_relations')
45
+ end.to raise_error(RestPack::Resource::InvalidInclude, "Artist.invalid_relations is not an includable relation")
46
+ end
47
+
48
+ it "should not allow includes that have not been specified with 'resource_can_include' NEW" do
49
+ expect do
50
+ Comment.paged_resource(:includes => 'songs')
51
+ end.to raise_error(RestPack::Resource::InvalidInclude, "Comment.songs is not an includable relation")
52
+ end
53
+
54
+ it "should not allow a 'has_many' include when paging" do
55
+ expect do
56
+ Artist.paged_resource(:includes => 'songs')
57
+ end.to raise_error(RestPack::Resource::InvalidInclude, "Artist.songs can't be included when paging artists")
58
+ end
59
+
60
+ it "should return related entities from a 'belongs_to' relationship" do
61
+ result = Song.paged_resource(:includes => 'artists')
62
+ result.should_not == nil
63
+ result[:artists].should_not == nil
64
+ result[:artists].size.should == 10
65
+ end
66
+
67
+ it "should allow multiple includes" do
68
+ result = Song.paged_resource(:includes => 'artists,users')
69
+ result.should_not == nil
70
+ result[:artists].should_not == nil
71
+ result[:artists].size.should == 10
72
+ result[:users].size.should == 20
73
+ end
74
+
75
+ it "should return related entities with their #to_resource representation" do
76
+ result = Song.paged_resource(:includes => 'users')
77
+ result[:users][0][:custom].should == 'This is custom data'
78
+ end
79
+
80
+ context "when specifying overrides" do
81
+ it "should give overrides precidence" do
82
+ result = Artist.paged_resource({ page: 2 }, { page: 3 })
83
+ result[:page].should == 3
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,50 @@
1
+ require './spec/spec_helper'
2
+ require './lib/restpack-resource'
3
+
4
+ describe RestPack::Resource do
5
+ context "Resource Setup" do
6
+ before :each do
7
+ class MyModel
8
+ include DataMapper::Resource
9
+ include RestPack::Resource
10
+ property :id, Serial
11
+ property :name, String
12
+ property :age, Integer
13
+ end
14
+ DataMapper.auto_migrate!
15
+ end
16
+
17
+ describe "#resource_can_include" do
18
+ it "allows association to be set" do
19
+ MyModel.resource_includable_associations.length == 0
20
+ class MyModel
21
+ resource_can_include :association1
22
+ resource_can_include :association2, :association3
23
+ end
24
+ MyModel.resource_includable_associations.should == [:association1, :association2, :association3]
25
+ end
26
+ end
27
+
28
+ describe "#resource_can_filter_by" do
29
+ it "allows filterable columns to be set" do
30
+ MyModel.resource_filterable_by.length == 0
31
+ class MyModel
32
+ resource_can_filter_by :id
33
+ resource_can_filter_by :name, :age
34
+ end
35
+ MyModel.resource_filterable_by.should == [:id, :name, :age]
36
+ end
37
+ end
38
+
39
+ describe "#resource_can_sort_by" do
40
+ it "allows sortable columns to be set" do
41
+ MyModel.resource_sortable_by.length == 0
42
+ class MyModel
43
+ resource_can_sort_by :id
44
+ resource_can_sort_by :name, :age
45
+ end
46
+ MyModel.resource_sortable_by.should == [:id, :name, :age]
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ require './spec/spec_helper'
2
+
3
+ describe RestPack::Resource do
4
+ describe "#paged_resource" do
5
+ context "when sorting" do
6
+ context "with invalid options" do
7
+ it "should not allow invalid sort column" do
8
+ expect do
9
+ Artist.paged_resource(:sort_by => :invalid_column)
10
+ end.to raise_error(RestPack::Resource::InvalidSortBy)
11
+ end
12
+ end
13
+
14
+ context "with valid options" do
15
+ before(:each) do
16
+ 20.times { create(:artist) }
17
+ end
18
+
19
+ it "should default to ascending" do
20
+ result = Artist.paged_resource(:sort_by => :id)
21
+ result[:total].should == Artist.count
22
+ result[:artists].first[:id].should == 1
23
+ result[:artists].last[:id].should == 10
24
+ end
25
+
26
+ it "should allow sort_direction of descending" do
27
+ result = Artist.paged_resource(:sort_by => :id, :sort_direction => :descending)
28
+ result[:total].should == Artist.count
29
+ result[:artists].first[:id].should == 20
30
+ result[:artists].last[:id].should == 11
31
+ end
32
+
33
+ it "should allow sort_by and sort_direction to be string or symbol" do
34
+ result = Artist.paged_resource(:sort_by => 'id', :sort_direction => 'descending')
35
+ result[:total].should == Artist.count
36
+ result = Artist.paged_resource(:sort_by => :id, :sort_direction => :descending)
37
+ result[:total].should == Artist.count
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,99 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup(:default, :test)
4
+
5
+ require 'dm-core'
6
+ require 'dm-timestamps'
7
+ require 'dm-validations'
8
+ require 'dm-aggregates'
9
+ require 'dm-migrations'
10
+ require 'dm-types'
11
+ require 'dm-serializer'
12
+ require 'dm-pager'
13
+ require 'factory_girl'
14
+
15
+ require './lib/restpack-resource'
16
+
17
+ ENV["RACK_ENV"] ||= 'test'
18
+
19
+ DataMapper.setup(:default, "sqlite3::memory:")
20
+ DataMapper::Model.raise_on_save_failure = true
21
+ DataMapper::Pagination.defaults[:per_page] = 10
22
+
23
+
24
+ class Artist
25
+ include DataMapper::Resource
26
+ include RestPack::Resource
27
+ property :id, Serial
28
+ property :name, String
29
+ #timestamps :at #NOTE: GJ: FactoryGirl is not saving when DM timestamps are used
30
+
31
+ validates_presence_of :name
32
+ has n, :songs
33
+
34
+ resource_can_include :songs
35
+ resource_can_sort_by :id, :name
36
+ end
37
+
38
+ class Song
39
+ include DataMapper::Resource
40
+ include RestPack::Resource
41
+ property :id, Serial
42
+ property :name, String
43
+ property :artist_id, Integer
44
+ property :created_by, Integer
45
+ property :modified_by, Integer
46
+ #timestamps :at
47
+
48
+ validates_presence_of :name
49
+ belongs_to :artist
50
+ belongs_to :creator, 'User', :child_key => [ :created_by ]
51
+ belongs_to :modifier, 'User', :child_key => [ :modified_by ]
52
+ has n, :comments
53
+
54
+ resource_can_include :artists, :users
55
+ resource_can_filter_by :artist_id
56
+ end
57
+
58
+ class Comment
59
+ include DataMapper::Resource
60
+ include RestPack::Resource
61
+ property :id, Serial
62
+ property :song_id, Integer
63
+ property :text, String
64
+ #timestamps :at
65
+
66
+ validates_presence_of :text
67
+ belongs_to :song
68
+ end
69
+
70
+ class User
71
+ include DataMapper::Resource
72
+ include RestPack::Resource
73
+ property :id, Serial
74
+ property :name, String
75
+ #timestamps :at
76
+
77
+ def to_resource
78
+ {
79
+ id: id,
80
+ name: name,
81
+ custom: "This is custom data"
82
+ }
83
+ end
84
+ end
85
+
86
+ FactoryGirl.find_definitions
87
+
88
+ RSpec.configure do |config|
89
+ config.treat_symbols_as_metadata_keys_with_true_values = true
90
+ config.run_all_when_everything_filtered = true
91
+ config.filter_run :focus
92
+ config.order = 'random'
93
+
94
+ config.include FactoryGirl::Syntax::Methods
95
+
96
+ config.before(:each) do
97
+ DataMapper.auto_migrate!
98
+ end
99
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: restpack-resource
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Gavin Joyce
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: active_support
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 3.0.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '2.12'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2.12'
46
+ description: RESTful resource paging, side-loading, filtering and sorting
47
+ email:
48
+ - gavinjoyce@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - .rspec
55
+ - .travis.yml
56
+ - Gemfile
57
+ - Gemfile.lock
58
+ - LICENSE
59
+ - README.md
60
+ - Rakefile
61
+ - lib/restpack-resource.rb
62
+ - lib/restpack-resource/resource.rb
63
+ - lib/restpack-resource/resource/filterable.rb
64
+ - lib/restpack-resource/resource/includable.rb
65
+ - lib/restpack-resource/resource/pageable.rb
66
+ - lib/restpack-resource/resource/sortable.rb
67
+ - lib/restpack-resource/version.rb
68
+ - restpack-resource.gemspec
69
+ - spec/factories.rb
70
+ - spec/resource/filterable_spec.rb
71
+ - spec/resource/pageable_spec.rb
72
+ - spec/resource/resource_spec.rb
73
+ - spec/resource/sortable_spec.rb
74
+ - spec/spec_helper.rb
75
+ homepage: https://github.com/RESTpack/restpack-resource
76
+ licenses: []
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 1.8.23
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: ! '...'
99
+ test_files:
100
+ - spec/factories.rb
101
+ - spec/resource/filterable_spec.rb
102
+ - spec/resource/pageable_spec.rb
103
+ - spec/resource/resource_spec.rb
104
+ - spec/resource/sortable_spec.rb
105
+ - spec/spec_helper.rb