hypa 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 28d59bb2cad450e802dec69f3be3504452ae06d8
4
- data.tar.gz: 5ee7de39652bc9aa30f6ed7fdba7e6ce93bc47d2
3
+ metadata.gz: 4ab61fe787dba85c43941f98b2edeae319a7dccb
4
+ data.tar.gz: 027ea139b2f90ff9c27d6285aa8bd3a1d7e07e05
5
5
  SHA512:
6
- metadata.gz: 646d4101496edf2411102046db7fa7e3ea0ac411564027d102cbc4bee6e67a6e3ae4aa32bc20cbda53e3738d2284f5cfe6748cd87838384086b14b668b14ef6f
7
- data.tar.gz: 16ecce86ef0630d56568e02b202e5de285d5f6d965c38348be73534be8eee8e4c249806ad0e2c248ea32edcdf91da88b6e527af8ea764c6891e7a22763f80817
6
+ metadata.gz: bd2f20ff25e4f4277df85623564ed534717bfcbc360d38e0f468bbb0870a74987e8d860ae16e41ce41278fdb42a0c0248e93665d58e78c3c3e970113d08b7111
7
+ data.tar.gz: a49106096218c76ba4c77b758bdbb5ccc7ae684dd41e9863ba0a464b415e7d453d5b3c5ff231a04fe74c8994a85525c97f65eb53ade6ac48d6959bf958f81feb
@@ -1,6 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0.0
4
3
  - 1.9.3
4
+ - jruby-19mode
5
+ - jruby-head
5
6
  - rbx-19mode
7
+ - 2.0.0
6
8
  - ruby-head
@@ -1,19 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hypa (0.0.1)
5
- addressable
4
+ hypa (0.0.2)
6
5
  extlib
7
- multi_json
8
- sequel
9
- sinatra
10
- virtus
11
6
 
12
7
  GEM
13
8
  remote: https://rubygems.org/
14
9
  specs:
15
- addressable (2.3.4)
16
- backports (2.6.7)
17
10
  colorize (0.5.8)
18
11
  coveralls (0.6.7)
19
12
  colorize
@@ -21,19 +14,10 @@ GEM
21
14
  rest-client
22
15
  simplecov (>= 0.7)
23
16
  thor
24
- descendants_tracker (0.0.1)
25
17
  diff-lcs (1.2.4)
26
18
  extlib (0.9.16)
27
19
  mime-types (1.23)
28
20
  multi_json (1.7.2)
29
- oj (2.0.12)
30
- puma (2.0.1)
31
- rack (>= 1.1, < 2.0)
32
- rack (1.5.2)
33
- rack-protection (1.5.0)
34
- rack
35
- rack-test (0.6.2)
36
- rack (>= 1.0)
37
21
  rake (0.9.6)
38
22
  rest-client (1.6.7)
39
23
  mime-types (>= 1.16)
@@ -45,21 +29,11 @@ GEM
45
29
  rspec-expectations (2.13.0)
46
30
  diff-lcs (>= 1.1.3, < 2.0)
47
31
  rspec-mocks (2.13.1)
48
- sequel (3.47.0)
49
32
  simplecov (0.7.1)
50
33
  multi_json (~> 1.0)
51
34
  simplecov-html (~> 0.7.1)
52
35
  simplecov-html (0.7.1)
53
- sinatra (1.4.2)
54
- rack (~> 1.5, >= 1.5.2)
55
- rack-protection (~> 1.4)
56
- tilt (~> 1.3, >= 1.3.4)
57
- sqlite3 (1.3.7)
58
36
  thor (0.18.1)
59
- tilt (1.4.0)
60
- virtus (0.5.4)
61
- backports (~> 2.6.1)
62
- descendants_tracker (~> 0.0.1)
63
37
 
64
38
  PLATFORMS
65
39
  ruby
@@ -67,10 +41,6 @@ PLATFORMS
67
41
  DEPENDENCIES
68
42
  coveralls
69
43
  hypa!
70
- oj
71
- puma
72
- rack-test
73
44
  rake
74
45
  rspec
75
46
  simplecov
76
- sqlite3
data/README.md CHANGED
@@ -1,3 +1,18 @@
1
1
  # Hypa: Web Framework to make Hypermedia APIs
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/hypa.png)] [![Build Status](https://travis-ci.org/nmerouze/hypa.png?branch=master)](https://travis-ci.org/nmerouze/hypa) [![Code Climate](https://codeclimate.com/github/nmerouze/hypa.png)](https://codeclimate.com/github/nmerouze/hypa) [![Dependency Status](https://gemnasium.com/nmerouze/hypa.png)](https://gemnasium.com/nmerouze/hypa) [![Coverage Status](https://coveralls.io/repos/nmerouze/hypa/badge.png?branch=master)](https://coveralls.io/r/nmerouze/hypa)
3
+ [![Gem Version](https://badge.fury.io/rb/hypa.png)](http://rubygems.org/gems/hypa) [![Build Status](https://travis-ci.org/nmerouze/hypa.png?branch=master)](https://travis-ci.org/nmerouze/hypa) [![Code Climate](https://codeclimate.com/github/nmerouze/hypa.png)](https://codeclimate.com/github/nmerouze/hypa) [![Dependency Status](https://gemnasium.com/nmerouze/hypa.png)](https://gemnasium.com/nmerouze/hypa) [![Coverage Status](https://coveralls.io/repos/nmerouze/hypa/badge.png?branch=master)](https://coveralls.io/r/nmerouze/hypa)
4
+
5
+ # List of Hypermedia content types
6
+
7
+ * Collection+JSON
8
+ * HAL
9
+ * Siren
10
+ * [JSON API](http://jsonapi.org)
11
+
12
+ # TODO
13
+
14
+ * Root element should be the name of the collection
15
+ * Refactoring and improve Collection#render
16
+ * Nested attribute sets
17
+ * Filter a hash through action params
18
+ * More features (descriptions, validations, etc)
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'sinatra'
4
+ gem 'multi_json'
5
+ gem 'oj'
6
+ gem 'puma'
7
+ gem 'sequel'
8
+ gem 'sqlite3'
9
+ gem 'hypa', path: '../../'
@@ -0,0 +1,36 @@
1
+ PATH
2
+ remote: ../../
3
+ specs:
4
+ hypa (0.0.2)
5
+ extlib
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ extlib (0.9.16)
11
+ multi_json (1.7.2)
12
+ oj (2.0.12)
13
+ puma (2.0.1)
14
+ rack (>= 1.1, < 2.0)
15
+ rack (1.5.2)
16
+ rack-protection (1.5.0)
17
+ rack
18
+ sequel (3.47.0)
19
+ sinatra (1.4.2)
20
+ rack (~> 1.5, >= 1.5.2)
21
+ rack-protection (~> 1.4)
22
+ tilt (~> 1.3, >= 1.3.4)
23
+ sqlite3 (1.3.7)
24
+ tilt (1.4.0)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ hypa!
31
+ multi_json
32
+ oj
33
+ puma
34
+ sequel
35
+ sinatra
36
+ sqlite3
@@ -0,0 +1,55 @@
1
+ require 'bundler/setup'
2
+ require 'sinatra'
3
+ require 'sequel'
4
+ require 'multi_json'
5
+ require 'hypa'
6
+
7
+ DB = Sequel.sqlite
8
+
9
+ DB.create_table(:posts) do
10
+ primary_key :id
11
+ String :title
12
+ String :body
13
+ end
14
+
15
+ class Post < Sequel::Model
16
+ end
17
+
18
+ Post.insert(title: 'First Title', body: 'This is the first post')
19
+
20
+ class Blog < Hypa::Application
21
+ end
22
+
23
+ Blog.collection :posts do |c|
24
+ c.schema do |s|
25
+ s.attribute :id, type: 'integer'
26
+ s.attribute :title, type: 'string'
27
+ s.attribute :body, type: 'string'
28
+ end
29
+
30
+ c.action do |a|
31
+ a.rel :self
32
+ a.href '/posts'
33
+
34
+ a.params do |p|
35
+ p.attribute :limit, type: 'integer'
36
+ # p.set :title do |s|
37
+ # s.attribute :in, type: 'array'
38
+ # s.attribute :like, type: 'string'
39
+ # end
40
+ end
41
+ end
42
+ end
43
+
44
+ before do
45
+ content_type 'application/hypa+json'
46
+ end
47
+
48
+ include Sinatra
49
+
50
+ get '/posts' do
51
+ template = Blog.collections[:posts]
52
+ # parameters = template.actions[:self].filter(params)
53
+ posts = Post.all#(parameters)
54
+ MultiJson.dump(template.render(posts))
55
+ end
@@ -17,19 +17,10 @@ Gem::Specification.new do |s|
17
17
  s.require_path = 'lib'
18
18
  s.required_ruby_version = '>= 1.9.3'
19
19
 
20
- s.add_dependency 'virtus'
21
20
  s.add_dependency 'extlib'
22
- s.add_dependency 'multi_json'
23
- s.add_dependency 'sinatra'
24
- s.add_dependency 'addressable'
25
- s.add_dependency 'sequel'
26
21
 
27
22
  s.add_development_dependency 'rspec'
28
- s.add_development_dependency 'rack-test'
29
23
  s.add_development_dependency 'rake'
30
- s.add_development_dependency 'sqlite3'
31
- s.add_development_dependency 'oj'
32
- s.add_development_dependency 'puma'
33
24
  s.add_development_dependency 'simplecov'
34
25
  s.add_development_dependency 'coveralls'
35
26
  end
@@ -1,158 +1,103 @@
1
1
  # encoding: utf-8
2
-
3
2
  require 'bundler/setup'
4
- require 'virtus'
5
- require 'sinatra'
6
- require 'multi_json'
7
- require 'addressable/template'
8
- require 'rack/utils'
9
3
  require 'extlib/class'
10
- require 'extlib/inflection'
11
4
 
12
5
  module Hypa
13
6
  class Attribute
14
- include Virtus
15
-
16
- attribute :name, String
17
- attribute :value, String
18
- attribute :prompt, String
19
- end
7
+ attr_reader :name, :type
20
8
 
21
- class Link
22
- include Virtus
23
-
24
- attribute :rel, String
25
- attribute :href, String
26
- end
27
-
28
- class Item
29
- include Virtus
30
-
31
- attribute :href, String
32
- attribute :data, Array[Attribute]
33
- attribute :links, Array[Link]
34
-
35
- def render(data)
36
- self.href = Addressable::Template.new(self.href).expand(data).to_s
37
- self.data.each { |a| a.value = Rack::Utils.unescape(Addressable::Template.new(a.value).expand(data).to_s) }
38
- self
9
+ def initialize(properties = {})
10
+ @name = properties.delete(:name)
11
+ @type = properties.delete(:type)
39
12
  end
40
- end
41
-
42
- class Template
43
- include Virtus
44
13
 
45
- attribute :data, Array[Attribute]
14
+ def to_hash
15
+ { name: @name.to_s, type: @type.to_s }
16
+ end
46
17
  end
47
18
 
48
- class Query
49
- include Virtus
19
+ class AttributeSet
20
+ attr_reader :attributes
50
21
 
51
- attribute :data, Array[Attribute]
52
- attribute :rel, String
53
- attribute :href, String
54
- attribute :prompt, String
55
- end
22
+ def initialize(&block)
23
+ @attributes = []
24
+ block.call(self) if block_given?
25
+ end
56
26
 
57
- class Collection
58
- include Virtus
59
-
60
- attribute :version, String
61
- attribute :href, String
62
- attribute :links, Array[Link]
63
- attribute :items, Array[Item]
64
- attribute :template, Template
65
- attribute :queries, Array[Query]
66
- end
27
+ def attribute(name, properties = {})
28
+ @attributes << Attribute.new(properties.merge(name: name))
29
+ end
67
30
 
68
- class Database
69
- cattr_accessor :connection
31
+ # def set(name, &block)
32
+ # @sets[name] << AttributeSet.new(&block)
33
+ # end
70
34
 
71
- def self.all(coll_name)
72
- @@connection.from(coll_name).all
35
+ def to_hash
36
+ @attributes.map { |a| a.to_hash }
73
37
  end
74
38
  end
75
39
 
76
- class Application < Sinatra::Base
77
- cattr_accessor :templates, :collections, :items
78
-
79
- set :show_exceptions, false
80
-
81
- before do
82
- content_type 'application/vnd.collection+json'
40
+ class Action
41
+ def initialize(&block)
42
+ block.call(self) if block_given?
83
43
  end
84
44
 
85
- get '/:collection' do
86
- coll_name = params[:collection]
87
-
88
- if collection = @@collections[coll_name.to_sym]
89
- items = Database.all(coll_name)
90
-
91
- collection.items = items.map do |data|
92
- @@items[coll_name.singular.to_sym].clone.render(data)
93
- end
94
-
95
- MultiJson.dump(collection.to_hash, mode: :compat)
96
- else
97
- status 404
98
- MultiJson.dump({ error: 'Not found.' }, mode: :compat)
99
- end
45
+ def rel(value)
46
+ @rel = value
100
47
  end
101
48
 
102
- get '/:collection/:id' do
49
+ def href(value)
50
+ @href = value
103
51
  end
104
52
 
105
- post '/:collection' do
53
+ def params(&block)
54
+ @params = AttributeSet.new(&block)
106
55
  end
107
56
 
108
- patch '/:collection/:id' do
57
+ def to_hash
58
+ { rel: @rel.to_s, href: @href.to_s, params: @params.to_hash }
109
59
  end
60
+ end
110
61
 
111
- delete '/:collection/:id' do
62
+ class Collection
63
+ def initialize(&block)
64
+ @actions = []
65
+ block.call(self) if block_given?
112
66
  end
113
67
 
114
- class << self
115
- def template(name, &block)
116
- @@templates ||= {}
117
-
118
- if block_given?
119
- template = Template.new
120
- block.call(template)
121
- @@templates[name] = template
122
- else
123
- template = @@templates[name]
124
- end
68
+ def schema(&block)
69
+ @schema = AttributeSet.new(&block)
70
+ end
125
71
 
126
- template
127
- end
72
+ def action(&block)
73
+ @actions << Action.new(&block)
74
+ end
128
75
 
129
- def collection(name, &block)
130
- @@collections ||= {}
76
+ def to_hash
77
+ { schema: @schema.to_hash, actions: @actions.map { |a| a.to_hash } }
78
+ end
131
79
 
132
- if block_given?
133
- collection = Collection.new
134
- block.call(collection)
135
- @@collections[name] = collection
136
- else
137
- collection = @@collections[name]
138
- end
80
+ # TODO: Refactoring
81
+ def render(data)
82
+ attributes = @schema.attributes.map { |a| a.name }
139
83
 
140
- collection
84
+ items = data.map do |d|
85
+ item = {}
86
+ attributes.each { |a| item[a] = d[a] }
87
+ item
141
88
  end
89
+
90
+ self.to_hash.merge(items: items)
91
+ end
92
+ end
142
93
 
143
- def item(name, &block)
144
- @@items ||= {}
94
+ class Application
95
+ cattr_reader :collections
145
96
 
146
- if block_given?
147
- item = Item.new
148
- block.call(item)
149
- @@items[name] = item
150
- else
151
- item = @@items[name]
152
- end
97
+ @@collections = {}
153
98
 
154
- item
155
- end
99
+ def self.collection(name, &block)
100
+ @@collections[name] = Collection.new(&block)
156
101
  end
157
102
  end
158
103
  end
@@ -1,3 +1,3 @@
1
1
  module Hypa
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Hypa::Action.new' do
4
+ before do
5
+ @action = Hypa::Action.new do |a|
6
+ a.rel :self
7
+ a.href '/posts'
8
+
9
+ a.params do |p|
10
+ p.attribute :title, type: 'string'
11
+ end
12
+ end
13
+
14
+ @properties = @action.to_hash
15
+ end
16
+
17
+ it 'defines rel, href and params' do
18
+ expect(@properties[:rel]).to eq('self')
19
+ expect(@properties[:href]).to eq('/posts')
20
+ expect(@properties[:params]).to eq([{ name: 'title', type: 'string' }])
21
+ end
22
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hypa::Collection, '.new' do
4
+ before do
5
+ @resource = Hypa::Collection.new do |c|
6
+ c.schema do |s|
7
+ s.attribute(:title, type: 'string')
8
+ end
9
+
10
+ c.action do |a|
11
+ a.rel :search
12
+ a.href '/posts/search'
13
+
14
+ a.params do |p|
15
+ p.attribute :q, type: 'string'
16
+ end
17
+ end
18
+ end
19
+
20
+ @properties = @resource.to_hash
21
+ end
22
+
23
+ it 'defines schema' do
24
+ expect(@properties[:schema]).to eq([{ name: 'title', type: 'string' }])
25
+ end
26
+
27
+ it 'defines actions' do
28
+ expect(@properties[:actions]).to eq([{ rel: 'search', href: '/posts/search', params: [{ name: 'q', type: 'string' }] }])
29
+ end
30
+ end
31
+
32
+ describe Hypa::Collection, '#render' do
33
+ before do
34
+ @resource = Hypa::Collection.new do |c|
35
+ c.schema do |s|
36
+ s.attribute(:title, type: 'string')
37
+ end
38
+ end
39
+
40
+ @properties = @resource.render([{ title: 'My Test Title' }])
41
+ end
42
+
43
+ it 'renders items of the resource' do
44
+ expect(@properties[:items]).to eq([{ title: 'My Test Title' }])
45
+ end
46
+ end
@@ -1,7 +1,5 @@
1
1
  # encoding: utf-8
2
-
3
2
  require 'bundler/setup'
4
- require 'rack/test'
5
3
  require 'simplecov'
6
4
  require 'coveralls'
7
5
 
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hypa::Attribute, '#initialize' do
4
+ before do
5
+ @attribute = Hypa::Attribute.new(name: 'title', type: 'string')
6
+ end
7
+
8
+ it 'stores name' do
9
+ expect(@attribute.name).to eq('title')
10
+ end
11
+
12
+ it 'stores type' do
13
+ expect(@attribute.type).to eq('string')
14
+ end
15
+ end
16
+
17
+ describe Hypa::AttributeSet, '#attribute' do
18
+ before do
19
+ @attribute = double('Hypa::Attribute')
20
+ Hypa::Attribute.stub(:new).and_return(@attribute)
21
+ @set = Hypa::AttributeSet.new
22
+ end
23
+
24
+ it 'initializes attribute with name and type' do
25
+ Hypa::Attribute.should_receive(:new).with(name: 'title', type: 'string')
26
+ @set.attribute('title', type: 'string')
27
+ end
28
+
29
+ it 'stores attribute' do
30
+ @set.attribute('title', type: 'string')
31
+ expect(@set.attributes).to eq([@attribute])
32
+ end
33
+ end
34
+
35
+ # describe Hypa::Action, '#to_hash' do
36
+ # it 'serializes properties to a hash'
37
+ # it 'casts rel to string'
38
+ # it 'casts href to string'
39
+ # it 'serializes params'
40
+ # end
41
+
42
+ # describe Hypa::AttributeSet, '#to_hash' do
43
+ # it 'serializes attributes into an array of hashes'
44
+ # end
45
+
46
+ # describe Hypa::Attribute, '#to_hash' do
47
+ # it 'serializes properties to a hash'
48
+ # it 'casts name to string'
49
+ # it 'casts type to string'
50
+ # end
51
+
52
+ describe Hypa::Application, '.collection' do
53
+ it 'stores a resource' do
54
+ Hypa::Application.collection :posts, &Proc.new {}
55
+ expect(Hypa::Application.collections[:posts]).to be_a(Hypa::Collection)
56
+ end
57
+ end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hypa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicolas Mérouze
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-03 00:00:00.000000000 Z
11
+ date: 2013-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: virtus
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - '>='
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - '>='
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: extlib
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -38,62 +24,6 @@ dependencies:
38
24
  - - '>='
39
25
  - !ruby/object:Gem::Version
40
26
  version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: multi_json
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - '>='
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: sinatra
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - '>='
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: addressable
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - '>='
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - '>='
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: sequel
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - '>='
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - '>='
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
27
  - !ruby/object:Gem::Dependency
98
28
  name: rspec
99
29
  requirement: !ruby/object:Gem::Requirement
@@ -108,20 +38,6 @@ dependencies:
108
38
  - - '>='
109
39
  - !ruby/object:Gem::Version
110
40
  version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: rack-test
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - '>='
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - '>='
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
41
  - !ruby/object:Gem::Dependency
126
42
  name: rake
127
43
  requirement: !ruby/object:Gem::Requirement
@@ -136,48 +52,6 @@ dependencies:
136
52
  - - '>='
137
53
  - !ruby/object:Gem::Version
138
54
  version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: sqlite3
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - '>='
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - '>='
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: oj
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - '>='
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - '>='
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
- - !ruby/object:Gem::Dependency
168
- name: puma
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - '>='
172
- - !ruby/object:Gem::Version
173
- version: '0'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - '>='
179
- - !ruby/object:Gem::Version
180
- version: '0'
181
55
  - !ruby/object:Gem::Dependency
182
56
  name: simplecov
183
57
  requirement: !ruby/object:Gem::Requirement
@@ -221,12 +95,16 @@ files:
221
95
  - Gemfile.lock
222
96
  - README.md
223
97
  - Rakefile
224
- - examples/todo.rb
98
+ - examples/sinatra/Gemfile
99
+ - examples/sinatra/Gemfile.lock
100
+ - examples/sinatra/application.rb
225
101
  - hypa.gemspec
226
102
  - lib/hypa.rb
227
103
  - lib/hypa/version.rb
228
- - spec/lib/hypa_spec.rb
104
+ - spec/integration/action_spec.rb
105
+ - spec/integration/collection_spec.rb
229
106
  - spec/spec_helper.rb
107
+ - spec/unit/hypa_spec.rb
230
108
  homepage: https://github.com/nmerouze/hypa
231
109
  licenses:
232
110
  - MIT
@@ -252,5 +130,7 @@ signing_key:
252
130
  specification_version: 4
253
131
  summary: Web Framework to make Hypermedia APIs
254
132
  test_files:
255
- - spec/lib/hypa_spec.rb
133
+ - spec/integration/action_spec.rb
134
+ - spec/integration/collection_spec.rb
256
135
  - spec/spec_helper.rb
136
+ - spec/unit/hypa_spec.rb
@@ -1,52 +0,0 @@
1
- require File.expand_path('../../lib/hypa', __FILE__)
2
- require 'sequel'
3
-
4
- Hypa::Database.connection = Sequel.sqlite
5
-
6
- Hypa::Database.connection.create_table(:posts) do
7
- primary_key :id
8
- String :title
9
- end
10
-
11
- Hypa::Database.connection.from(:posts).insert(title: 'What a title!')
12
-
13
- class Todo < Hypa::Application
14
- end
15
-
16
- Todo.item :post do |i|
17
- i.href = '/posts/{id}'
18
-
19
- i.data = [
20
- { name: 'title', value: '{title}', prompt: 'Title' }
21
- ]
22
- end
23
-
24
- Todo.template :post do |t|
25
- t.data = [
26
- { name: 'title', value: '', prompt: 'Title' }
27
- ]
28
- end
29
-
30
- Todo.template :search do |t|
31
- t.data = [
32
- { name: 'q', value: '', prompt: 'Search' }
33
- ]
34
- end
35
-
36
- Todo.collection :posts do |c|
37
- c.version = '1.0'
38
- c.href = '/posts'
39
-
40
- c.links = [
41
- { rel: 'feed', href: '/posts/feed' }
42
- ]
43
-
44
- c.queries = [
45
- { rel: 'search', href: '/posts/search', prompt: 'Search', data: Todo.template(:search).data }
46
- ]
47
-
48
- c.template = Todo.template(:post)
49
- end
50
-
51
- # https://github.com/rkh/mustermann
52
- # https://github.com/awslabs/seahorse
@@ -1,294 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- describe Hypa::Attribute do
6
- it 'stores name' do
7
- a = Hypa::Attribute.new(:name => 'full_name')
8
- expect(a.name).to eq('full_name')
9
- end
10
-
11
- it 'stores value' do
12
- a = Hypa::Attribute.new(:value => 'Nicolas Mérouze')
13
- expect(a.value).to eq('Nicolas Mérouze')
14
- end
15
-
16
- it 'stores prompt' do
17
- a = Hypa::Attribute.new(:prompt => 'Full Name')
18
- expect(a.prompt).to eq('Full Name')
19
- end
20
- end
21
-
22
- describe Hypa::Link do
23
- it 'stores rel' do
24
- l = Hypa::Link.new(:rel => 'feed')
25
- expect(l.rel).to eq('feed')
26
- end
27
-
28
- it 'stores href' do
29
- l = Hypa::Link.new(:href => 'http://example.org/posts/feed')
30
- expect(l.href).to eq('http://example.org/posts/feed')
31
- end
32
- end
33
-
34
- describe Hypa::Item do
35
- it 'stores href' do
36
- i = Hypa::Item.new(:href => 'http://example.org/posts/1')
37
- expect(i.href).to eq('http://example.org/posts/1')
38
- end
39
-
40
- it 'stores data' do
41
- a = Hypa::Attribute.new
42
- item = Hypa::Item.new(:data => [a])
43
- expect(item.data).to eq([a])
44
- end
45
-
46
- it 'stores links' do
47
- i = Hypa::Item.new(:links => [])
48
- expect(i.links).to eq([])
49
- end
50
- end
51
-
52
- describe Hypa::Item, '#render' do
53
- before do
54
- @item = Hypa::Item.new(href: '/posts/{id}', data: [
55
- { name: 'title', value: '{title}', prompt: 'Title' }
56
- ])
57
- @item.render(id: 1, title: 'My Custom Title')
58
- end
59
-
60
- it 'renders href with passed data' do
61
- expect(@item.href).to eq('/posts/1')
62
- end
63
-
64
- it 'renders data values with passed data' do
65
- expect(@item.data.first[:value]).to eq('My Custom Title')
66
- end
67
- end
68
-
69
- describe Hypa::Template do
70
- it 'stores data' do
71
- a = Hypa::Attribute.new
72
- t = Hypa::Template.new(:data => [a])
73
- expect(t.data).to eq([a])
74
- end
75
- end
76
-
77
- describe Hypa::Query do
78
- it 'stores data' do
79
- a = Hypa::Attribute.new
80
- q = Hypa::Query.new(:data => [a])
81
- expect(q.data).to eq([a])
82
- end
83
-
84
- it 'stores rel' do
85
- q = Hypa::Query.new(:rel => 'feed')
86
- expect(q.rel).to eq('feed')
87
- end
88
-
89
- it 'stores href' do
90
- q = Hypa::Link.new(:href => 'http://example.org/posts/feed')
91
- expect(q.href).to eq('http://example.org/posts/feed')
92
- end
93
-
94
- it 'stores prompt' do
95
- q = Hypa::Query.new(:prompt => 'Full Name')
96
- expect(q.prompt).to eq('Full Name')
97
- end
98
- end
99
-
100
- describe Hypa::Collection do
101
- it 'stores version' do
102
- c = Hypa::Collection.new(:version => '1.0')
103
- expect(c.version).to eq('1.0')
104
- end
105
-
106
- it 'stores href' do
107
- c = Hypa::Collection.new(:href => 'http://example.org/posts/')
108
- expect(c.href).to eq('http://example.org/posts/')
109
- end
110
-
111
- it 'stores links' do
112
- l = Hypa::Link.new
113
- c = Hypa::Collection.new(:links => [l])
114
- expect(c.links).to eq([l])
115
- end
116
-
117
- it 'stores items' do
118
- i = Hypa::Item.new
119
- c = Hypa::Collection.new(:items => [i])
120
- expect(c.items).to eq([i])
121
- end
122
-
123
- it 'stores queries' do
124
- q = Hypa::Query.new
125
- c = Hypa::Collection.new(:queries => [q])
126
- expect(c.queries).to eq([q])
127
- end
128
-
129
- it 'stores template' do
130
- t = Hypa::Template.new
131
- c = Hypa::Collection.new(:template => t)
132
- expect(c.template).to eq(t)
133
- end
134
- end
135
-
136
- describe Hypa::Application, '.template' do
137
- before do
138
- @template = Hypa::Template.new
139
- Hypa::Template.stub(:new => @template)
140
-
141
- Hypa::Application.template :mock do |t|
142
- t.data = [
143
- { name: 'full_name', value: '', prompt: 'Full Name' }
144
- ]
145
- end
146
- end
147
-
148
- context 'with block' do
149
- it 'initializes a template with block' do
150
- expect(@template.data.size).to eq(1)
151
- expect(@template.data.first.attributes).to eq(name: 'full_name', value: '', prompt: 'Full Name')
152
- end
153
-
154
- it 'stores a template' do
155
- expect(Hypa::Application.templates).to eq({ mock: @template })
156
- end
157
- end
158
-
159
- context 'without block' do
160
- it 'returns a template' do
161
- expect(Hypa::Application.template(:mock)).to eq(@template)
162
- end
163
- end
164
- end
165
-
166
- describe Hypa::Application, '.collection' do
167
- before do
168
- @collection = Hypa::Collection.new
169
- Hypa::Collection.stub(:new => @collection)
170
-
171
- Hypa::Application.collection :mock do |c|
172
- c.version = 'custom version'
173
- end
174
- end
175
-
176
- context 'with block' do
177
- it 'initializes a collection with block' do
178
- expect(@collection.version).to eq('custom version')
179
- end
180
-
181
- it 'stores a collection' do
182
- expect(Hypa::Application.collections).to eq(mock: @collection)
183
- end
184
- end
185
-
186
- context 'without block' do
187
- it 'returns a collection' do
188
- expect(Hypa::Application.collection(:mock)).to eq(@collection)
189
- end
190
- end
191
- end
192
-
193
- describe Hypa::Application, '.item' do
194
- before do
195
- @item = Hypa::Item.new
196
- Hypa::Item.stub(:new => @item)
197
-
198
- Hypa::Application.item :mock do |i|
199
- i.href = '/posts/{id}'
200
- end
201
- end
202
-
203
- context 'with block' do
204
- it 'initializes am item with block' do
205
- expect(@item.href).to eq('/posts/{id}')
206
- end
207
-
208
- it 'stores a item' do
209
- expect(Hypa::Application.items).to eq(mock: @item)
210
- end
211
- end
212
-
213
- context 'without block' do
214
- it 'returns a item' do
215
- expect(Hypa::Application.item(:mock)).to eq(@item)
216
- end
217
- end
218
- end
219
-
220
- describe 'GET /:collection' do
221
- include Rack::Test::Methods
222
-
223
- def app
224
- Hypa::Application
225
- end
226
-
227
- context 'with existing collection' do
228
- before do
229
- Hypa::Database.stub(:all).and_return([{id: 1234, title: 'My Test'}])
230
- item
231
- template
232
- collection
233
- get '/posts'
234
- end
235
-
236
- it 'renders collection' do
237
- expect(last_response.body).to eq(MultiJson.dump(app.collection(:posts), mode: :compat))
238
- end
239
-
240
- it 'renders items' do
241
- body = MultiJson.load(last_response.body)
242
-
243
- expect(body['items'][0]).to eq({
244
- 'href' => '/posts/1234',
245
-
246
- 'links' => [],
247
-
248
- 'data' => [
249
- { 'name' => 'title', 'value' => 'My Test', 'prompt' => 'Title' }
250
- ]
251
- })
252
- end
253
- end
254
-
255
- context 'withouth existing collection' do
256
- before do
257
- template
258
- collection
259
- get '/fakes'
260
- end
261
-
262
- it 'renders 404' do
263
- expect(last_response.status).to eq(404)
264
- end
265
- end
266
-
267
- def item
268
- app.item :post do |i|
269
- i.href = '/posts/{id}'
270
-
271
- i.data = [
272
- { name: 'title', value: '{title}', prompt: 'Title' },
273
- ]
274
- end
275
- end
276
-
277
- def template
278
- app.template :post do |t|
279
- t.data = [
280
- { name: 'title', value: '', prompt: 'Title' },
281
- { name: 'body', value: '', prompt: 'Body' }
282
- ]
283
- end
284
- end
285
-
286
- def collection
287
- app.collection :posts do |c|
288
- c.version = '1.0'
289
- c.href = '/posts'
290
-
291
- c.template = app.template(:post)
292
- end
293
- end
294
- end