hypa 0.0.1 → 0.0.2

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