hook-client 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c369258ba544d32bf8658fec16b773009810d138
4
+ data.tar.gz: cf1eda4213eda65e81875dd4ef2cb219b6160ee7
5
+ SHA512:
6
+ metadata.gz: f069f6984f0d0f27cac78b0dfaa723ae9964786f048f1904a5b989121df2e4e6b9b31ad87f61846e7231b17ff9a4423dcef71a8b4edc724bb43f37b577208e2b
7
+ data.tar.gz: c2457a562ca1575585b8dc47baaaab14171722d67b1084d46708359b5423ed3e260deb31c40a4dd32322bcf15cc58be6379c07c21d3d54440cf40a1c98ed8ad2
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Doubleleft
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,64 @@
1
+ hook-ruby client ![Build status](https://travis-ci.org/doubleleft/hook-ruby.svg?branch=master)
2
+ ===
3
+
4
+ ruby client for [hook](github.com/doubleleft/hook/).
5
+
6
+ - [API Reference](http://doubleleft.github.io/hook-ruby).
7
+ - [RubyGem](http://rubygems.org/gems/hook-client)
8
+
9
+ Getting started:
10
+ ---
11
+
12
+ ```ruby
13
+ # Gemfile
14
+ gem 'hook-client'
15
+ ```
16
+
17
+ Basic usage:
18
+
19
+ ```ruby
20
+ require 'hook-client'
21
+ client = Hook::Client(:app_id => 1, :key => "something", :endpoint => "https://dl-api.heroku.com")
22
+ client.collection(:posts).create(:title => "Getting Started", :description => "Getting started with dl-api-ruby.")
23
+ puts client.collection(:posts).where(:title => "Getting Started").count
24
+ ```
25
+
26
+ For more examples, please see [our tests](spec).
27
+
28
+ Using it with Rails
29
+ ---
30
+
31
+ Set-up with your credentials:
32
+
33
+ ```ruby
34
+ Hook::Client.configure(
35
+ :app_id => 1,
36
+ :key => "1f143fde82d14643099ae45e6c98c8e1",
37
+ :endpoint => "https://dl-api.heroku.com"
38
+ )
39
+ ```
40
+
41
+ Define your models:
42
+
43
+ ```ruby
44
+ class Post
45
+ include Hook::Model
46
+
47
+ field :title
48
+ field :description
49
+
50
+ validates_presence_of :title
51
+ end
52
+ ```
53
+
54
+ Hook::Model's uses almost the same syntax as ActiveRecord, which you're already
55
+ familiar with.
56
+
57
+ You will be able to use any
58
+ [ActiveModel](https://github.com/rails/rails/tree/master/activemodel) goodies,
59
+ such as validation, serialization and dirty methods.
60
+
61
+ License
62
+ ---
63
+
64
+ MIT
@@ -0,0 +1,11 @@
1
+ module Hook
2
+ autoload :VERSION, 'hook-client/version'
3
+ autoload :Client, 'hook-client/client'
4
+
5
+ autoload :Keys, 'hook-client/keys'
6
+ autoload :Collection, 'hook-client/collection'
7
+ autoload :Channel, 'hook-client/channel'
8
+ autoload :Model, 'hook-client/model'
9
+
10
+ autoload :Extensions, 'hook-client/extensions'
11
+ end
@@ -0,0 +1,4 @@
1
+ module Hook
2
+ class Auth
3
+ end
4
+ end
@@ -0,0 +1,13 @@
1
+ module Hook
2
+ module Channel
3
+ autoload :SSE, 'hook-client/channel/sse'
4
+ autoload :WEBSOCKET, 'hook-client/channel/websocket'
5
+
6
+ def self.create(client, name, options = {})
7
+ channel_klass = (options.delete(:transport) || 'sse').upcase
8
+ collection = Collection.new(name, :channel => true)
9
+ self.const_get(channel_klass).new(client, collection, options)
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Hook
2
+ class SSE
3
+
4
+ def initialize
5
+ end
6
+
7
+ end
8
+ end
9
+
@@ -0,0 +1,4 @@
1
+ module Hook
2
+ class WEBSOCKET
3
+ end
4
+ end
@@ -0,0 +1,93 @@
1
+ require 'http'
2
+ require 'uri'
3
+
4
+ module Hook
5
+ class Client
6
+ class << self
7
+ attr_reader :instance
8
+ def configure(options = {})
9
+ @instance = self.new(options)
10
+ end
11
+ end
12
+
13
+ def initialize options = {}
14
+ @app_id = options.delete(:app_id)
15
+ @key = options.delete(:key)
16
+ @endpoint = options.delete(:endpoint) || options.delete(:url)
17
+ @endpoint = "#{@endpoint}/" unless @endpoint.end_with? "/"
18
+
19
+ @logger = options.delete(:logger)
20
+ end
21
+
22
+ def keys
23
+ Keys.new
24
+ end
25
+
26
+ def auth
27
+ Auth.new
28
+ end
29
+
30
+ def files
31
+ Files.new
32
+ end
33
+
34
+ def collection(name)
35
+ Collection.new(:name => name, :client => self)
36
+ end
37
+
38
+ def logger=(logger)
39
+ @logger = logger
40
+ end
41
+
42
+ def channel(name, options = {})
43
+ throw NotImplementedError.new("channels not implemented")
44
+ Channel.create(self, name, options)
45
+ end
46
+
47
+ def post segments, data
48
+ request :post, segments, data
49
+ end
50
+
51
+ def get segments, data = {}
52
+ request :get, segments, data
53
+ end
54
+
55
+ def put segments, data
56
+ request :put, segments, data
57
+ end
58
+
59
+ def remove segments, data = {}
60
+ request :delete, segments, data
61
+ end
62
+ alias_method :delete, :remove
63
+
64
+ protected
65
+ def request method, segments, data = {}
66
+ response = nil, headers = {
67
+ :accept => 'application/json',
68
+ 'X-App-Id' => @app_id,
69
+ 'X-App-Key' => @key,
70
+ 'User-Agent' => "hook-ruby"
71
+ }
72
+
73
+ if method == :get
74
+ segments = "#{segments}?#{URI::escape(data.to_json)}"
75
+ data = nil
76
+ end
77
+
78
+ if @logger
79
+ start_time = Time.now
80
+ end
81
+
82
+ response = HTTP.with(headers).send(method, "#{@endpoint}#{segments}", :json => data).to_s
83
+
84
+ if @logger
85
+ @logger.info "#{self.class.name} - #{(Time.now - start_time).round(3)}s - #{method.upcase} #{@endpoint}#{segments}"
86
+ end
87
+
88
+ # If JSON.parse don't suceed, return response as integer
89
+ JSON.parse(response) rescue JSON.parse("{\"value\":#{response}}")['value'] rescue response.to_i
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,285 @@
1
+ module Hook
2
+ class Collection
3
+
4
+ def initialize options = {}
5
+ @name = options.delete(:name)
6
+ @client = options.delete(:client) || Hook::Client.instance
7
+
8
+ segment = options.delete(:channel) ? "channel" : "collection"
9
+ @segments = "#{segment}/#{@name}"
10
+ reset!
11
+ end
12
+
13
+ # Find item by _id.
14
+ #
15
+ # @param _id [String]
16
+ # @return [Hash]
17
+ def find _id
18
+ if _id.kind_of?(Array)
19
+ self.where(:_id.in => _id).all
20
+ else
21
+ @client.get "#{@segments}/#{_id}"
22
+ end
23
+ end
24
+
25
+ # Return only the first result from the database
26
+ def first
27
+ @options[:first] = 1
28
+ self.query!
29
+ end
30
+
31
+ # Create an item into the collection
32
+ #
33
+ # @param data [Hash, Array] item or array of items
34
+ # @return [Hash, Array]
35
+ def create data
36
+ if data.kind_of?(Array)
37
+ # TODO: server should accept multiple items to create,
38
+ # instead of making multiple requests.
39
+ data.map {|item| self.create(item) }
40
+ else
41
+ @client.post @segments, data
42
+ end
43
+ end
44
+
45
+ # Retrieve the first item with the given params in the database,
46
+ # if not found this will create one.
47
+ #
48
+ # @param data [Hash] query and data to store
49
+ # @return [Hash]
50
+ def first_or_create data
51
+ @options[:first] = 1
52
+ @options[:data] = data
53
+ @client.post(@segments, self.build_query)
54
+ end
55
+
56
+ # Remove items by id, or by query
57
+ #
58
+ # @param _id [String, nil] _id
59
+ # @return [Hash] status of the operation (ex: {success: true, affected_rows: 7})
60
+ def remove _id = nil
61
+ path = @segments
62
+ path = "#{path}/#{_id}" if _id
63
+ @client.remove(path, build_query)
64
+ end
65
+
66
+ # Remove items by query. This is the same as calling `remove` without `_id` param.
67
+ # @see remove
68
+ def delete_all
69
+ self.remove(nil)
70
+ end
71
+
72
+ # Add where clause to the current query.
73
+ #
74
+ # Supported modifiers on fields: .gt, .gte, .lt, .lte, .ne, .in, .not_in, .nin, .like, .between, .not_between
75
+ #
76
+ # @param fields [Hash] fields and values to filter
77
+ # @param [String] operation (and, or)
78
+ #
79
+ # @example
80
+ # hook.collection(:movies).where({
81
+ # :name => "Hook",
82
+ # :year.gt => 1990
83
+ # })
84
+ #
85
+ # @example Using Range
86
+ # hook.collection(:movies).where({
87
+ # :name.like => "%panic%",
88
+ # :year.between => 1990..2014
89
+ # })
90
+ #
91
+ # @return [Collection] self
92
+ def where fields = {}, operation = 'and'
93
+ fields.each_pair do |k, value|
94
+ field = (k.respond_to?(:field) ? k.field : k).to_s
95
+ comparation = k.respond_to?(:comparation) ? k.comparation : '='
96
+
97
+ # Range syntatic sugar
98
+ value = [ value.first, value.last ] if value.kind_of?(Range)
99
+
100
+ @wheres << [field, comparation, value, operation]
101
+ end
102
+ self
103
+ end
104
+
105
+ # Add where clause with 'OR' operation to the current query.
106
+ # @param fields [Hash] fields and values to filter
107
+ # @return [Collection] self
108
+ def or_where fields = {}
109
+ self.where(fields, 'or')
110
+ end
111
+
112
+ # Add order clause to the query.
113
+ #
114
+ # @param fields [String] ...
115
+ # @return [Collection] self
116
+ def order fields
117
+ by_num = { 1 => 'asc', -1 => 'desc' }
118
+ ordering = []
119
+ fields.each_pair do |key, value|
120
+ ordering << [key.to_s, by_num[value] || value]
121
+ end
122
+ @ordering = ordering
123
+ self
124
+ end
125
+ alias_method :sort, :order
126
+
127
+ # Limit the number of results to retrieve.
128
+ #
129
+ # @param int [Integer]
130
+ # @return [Collection] self
131
+ def limit int
132
+ @limit = int
133
+ self
134
+ end
135
+
136
+ # @param int [Integer]
137
+ # @return [Collection] self
138
+ def offset int
139
+ @offset = int
140
+ self
141
+ end
142
+
143
+ # Run the query, and return all it's results.
144
+ # @yield You may use a block with all returned results
145
+ # @return [Array]
146
+ def all(&block)
147
+ rows = query!
148
+ yield rows if block_given?
149
+ rows
150
+ end
151
+
152
+ def query!
153
+ @client.get @segments, build_query
154
+ end
155
+
156
+ def method_missing method, *args, &block
157
+ if Enumerator.method_defined? method
158
+ Enumerator.new(self.all).send(method, args, block)
159
+ end
160
+
161
+ throw NoMethodError.new("#{self.class.name}: method '#{method}' not found")
162
+ end
163
+
164
+ # Specify the target field names to retrieve
165
+ #
166
+ # @param fields [String] ...
167
+ # @return [Collection] self
168
+ def select *fields
169
+ @options[:select] = fields
170
+ end
171
+
172
+ # Return related collection's data
173
+ #
174
+ # @param relationships [String] ...
175
+ #
176
+ # @example Retrieving a single relation
177
+ # hook.collection(:books).with(:publisher).each do |book|
178
+ # puts book[:name]
179
+ # puts book[:publisher][:name]
180
+ # end
181
+ #
182
+ # @example Retrieving multiple relations
183
+ # hook.collection(:books).with(:publisher, :author).each do |book|
184
+ # puts book[:name]
185
+ # puts book[:publisher][:name]
186
+ # puts book[:author][:name]
187
+ # end
188
+ #
189
+ # @return [Collection] self
190
+ def with *relationships
191
+ @options[:with] = relationships
192
+ self
193
+ end
194
+
195
+ # Group query results
196
+ # @param fields [String] ...
197
+ # @return [Collection] self
198
+ def group *fields
199
+ @group = fields
200
+ self
201
+ end
202
+
203
+ def count field = '*'
204
+ @options[:aggregation] = { :method => 'count', :field => field }
205
+ self.query!
206
+ end
207
+
208
+ def max field
209
+ @options[:aggregation] = { :method => :max, :field => field }
210
+ self.query!
211
+ end
212
+
213
+ def min field
214
+ @options[:aggregation] = { :method => :min, :field => field }
215
+ self.query!
216
+ end
217
+
218
+ def avg field
219
+ @options[:aggregation] = { :method => :avg, :field => field }
220
+ self.query!
221
+ end
222
+
223
+ def sum field
224
+ @options[:aggregation] = { :method => :sum, :field => field }
225
+ self.query!
226
+ end
227
+
228
+ def increment field, value = 1
229
+ @options[:operation] = { :method => 'increment', :field => field, :value => value }
230
+ self.query!
231
+ end
232
+
233
+ def decrement field, value = 1
234
+ @options[:operation] = { :method => 'decrement', :field => field, :value => value }
235
+ self.query!
236
+ end
237
+
238
+ def update _id, data
239
+ @client.post "#{@segments}/#{_id}", data
240
+ end
241
+
242
+ def update_all data
243
+ @options[:data] = data
244
+ @client.put @segments, build_query
245
+ end
246
+
247
+ def build_query
248
+ query = {}
249
+ query[:limit] = @limit if @limit
250
+ query[:offset] = @offset if @offset
251
+
252
+ query[:q] = @wheres unless @wheres.empty?
253
+ query[:s] = @ordering unless @ordering.empty?
254
+ query[:g] = @group unless @group.empty?
255
+
256
+ {
257
+ :paginate => 'p',
258
+ :first => 'f',
259
+ :aggregation => 'aggr',
260
+ :operation => 'op',
261
+ :data => 'data',
262
+ :with => 'with',
263
+ :select => 'select',
264
+ }.each_pair do |option, shortname|
265
+ query[ shortname ] = @options[ option ] if @options[ option ]
266
+ end
267
+
268
+ self.reset!
269
+ query
270
+ end
271
+
272
+ protected
273
+
274
+ def reset!
275
+ @wheres = []
276
+ @options = {}
277
+ @wheres = []
278
+ @ordering = []
279
+ @group = []
280
+ @limit = nil
281
+ @offset = nil
282
+ end
283
+
284
+ end
285
+ end
@@ -0,0 +1,12 @@
1
+ module Hook
2
+ module Extensions
3
+ autoload :Symbol, 'hook-client/extensions/symbol'
4
+
5
+ def self.eager_load!
6
+ self.constants.each {|const| self.const_get(const) }
7
+ end
8
+ end
9
+ end
10
+
11
+ # Load all the extensions
12
+ Hook::Extensions.eager_load!
@@ -0,0 +1,28 @@
1
+ module DL
2
+ module Extensions
3
+ module Symbol
4
+
5
+ {
6
+ :gt => '>',
7
+ :gte => '>=',
8
+ :lt => '<',
9
+ :lte => '<=',
10
+ :ne => '!=',
11
+ :in => 'in',
12
+ :not_in => 'not_in',
13
+ :nin => 'not_in', # alias
14
+ :like => 'like',
15
+ :between => 'between',
16
+ :not_between => 'not_between',
17
+ # :max_distance,
18
+ }.each_pair do |method, comparation|
19
+ define_method(method) do
20
+ OpenStruct.new(:field => self, :comparation => comparation)
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+
28
+ ::Symbol.__send__(:include, DL::Extensions::Symbol)
@@ -0,0 +1,26 @@
1
+ module Hook
2
+ class Keys
3
+
4
+ def initialize(options={})
5
+ @client = options.delete(:client) || Hook::Client.instance
6
+ end
7
+
8
+ # Return the unserialized value
9
+ #
10
+ # @param key [String, Symbol]
11
+ # @return [Object] value
12
+ def get(key)
13
+ @client.get("key/#{key}")
14
+ end
15
+
16
+ # Store serialized value
17
+ #
18
+ # @param key [String, Symbol] key
19
+ # @param value [Object] JSON serializable object
20
+ # @return [Object] The object you just stored.
21
+ def set(key, value)
22
+ @client.post("key/#{key}", { :value => value });
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,116 @@
1
+ require 'active_model'
2
+
3
+ module Hook
4
+ #
5
+ # Provides ActiveRecord/like methods for querying Collections
6
+ #
7
+ module Model
8
+ def self.included(base)
9
+ base.class_eval do
10
+ extend ClassMethods
11
+ extend ActiveModel::Naming
12
+ extend ActiveModel::Translation
13
+ extend ActiveModel::Callbacks
14
+ include ActiveModel::Validations
15
+ include ActiveModel::Conversion
16
+ include ActiveModel::Dirty
17
+ include ActiveModel::AttributeMethods
18
+ include ActiveModel::Serializers::JSON
19
+ include ActiveModel::Serializers::Xml
20
+
21
+ field :_id
22
+ end
23
+ end
24
+
25
+ module InstanceMethods
26
+ def initialize(attrs = {})
27
+ # is Hook::Client configured?
28
+ throw RuntimeError.new("Please use Hook::Client.configure.") unless Hook::Client.instance
29
+
30
+ @collection = Hook::Client.instance.collection(self.class.collection_name)
31
+ self.attributes = {}
32
+ attrs.each_pair do |name, value|
33
+ self.send(:"#{name}=", value) if self.respond_to?(:"#{name}")
34
+ end
35
+
36
+ # reset_changes
37
+ changes_applied if self._id
38
+ end
39
+
40
+ def save
41
+ return false if !self.changed? || !self.valid?
42
+
43
+ changes_applied
44
+ if self._id.nil?
45
+ self.attributes = @collection.update(self._id, attributes)
46
+ else
47
+ self.attributes = @collection.create(attributes)
48
+ end
49
+ self
50
+ end
51
+
52
+ def attributes=(attrs)
53
+ @attributes = attrs
54
+ end
55
+
56
+ def attributes
57
+ @attributes
58
+ end
59
+
60
+ def inspect
61
+ "#<#{self.class.name}: attributes=#{attributes.inspect}>"
62
+ end
63
+
64
+ # Delegator methods
65
+ def method_missing(m, *args, &block)
66
+ res = @collection.send(m, *args, &block)
67
+
68
+ # Check for success/error responses
69
+ if res.kind_of?(Hash) && res.length == 1
70
+ return res['success'] unless res['success'].nil?
71
+ throw RuntimeError.new(res['error']) unless res['error'].nil?
72
+ end
73
+
74
+ if (res.kind_of?(Hook::Collection))
75
+ self
76
+ else
77
+ (res.kind_of?(Array)) ? res.map {|r| self.class.new(r) } : self.class.new(res)
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ module ClassMethods
84
+ def collection_name(name = nil)
85
+ if name
86
+ @collection_name = name
87
+ else
88
+ @collection_name = ActiveModel::Naming.route_key(self)
89
+ end
90
+ end
91
+
92
+ def field name, options = {}
93
+ define_attribute_method name
94
+
95
+ # Define getter
96
+ define_method name do
97
+ # self.instance_variable_get("@#{name}")
98
+ attributes[name]
99
+ end
100
+
101
+ # Define setter
102
+ define_method "#{name}=" do |value|
103
+ self.send(:"#{name}_will_change!")
104
+ attributes[name] = value
105
+ end
106
+ end
107
+
108
+ def method_missing(m, *args, &block)
109
+ instance = self.new
110
+ instance.send(m, *args, &block)
111
+ end
112
+ end
113
+
114
+ include InstanceMethods
115
+ end
116
+ end
@@ -0,0 +1,3 @@
1
+ module Hook
2
+ VERSION = '0.2.0'
3
+ end
@@ -0,0 +1,11 @@
1
+ describe Hook::Client do
2
+
3
+ subject do
4
+ Hook::Client.instance
5
+ end
6
+
7
+ it "" do
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,68 @@
1
+ describe Hook::Collection do
2
+
3
+ subject do
4
+ Hook::Client.instance
5
+ end
6
+
7
+ it "should create new items to collection" do
8
+ user = subject.collection(:users).create(:name => "Endel", :newsletter => true)
9
+ expect(user['name']).to eq("Endel")
10
+ expect(user['newsletter']).to eq(true)
11
+ end
12
+
13
+ it "should query for items" do
14
+ rows = subject.collection(:users).where(:name => "Endel").all
15
+ expect(rows.length).to be > 0
16
+ end
17
+
18
+ it "should delete all items" do
19
+ # create a dummy item
20
+ subject.collection(:users).create(:name => "Endel", :newsletter => true)
21
+ # remove every items
22
+ subject.collection(:users).delete_all
23
+ rows = subject.collection(:users).where(:name => "Endel").all
24
+ expect(rows.length).to be == 0
25
+ end
26
+
27
+ it "general methods" do
28
+ subject.collection(:highscores).delete_all
29
+
30
+ one = created = subject.collection(:highscores).create(:player => "One", :score => 50)
31
+ expect(created['player']).to eq("One")
32
+ expect(created['score']).to eq(50)
33
+
34
+ two = subject.collection(:highscores).create(:player => "Two", :score => 100)
35
+ three = subject.collection(:highscores).create(:player => "Three", :score => 25)
36
+ four = subject.collection(:highscores).create(:player => "Four", :score => 10)
37
+ five = subject.collection(:highscores).create(:player => "Five", :score => 150)
38
+ six = subject.collection(:highscores).create(:player => "Six", :score => 125)
39
+
40
+ # find multiple by id
41
+ rows = subject.collection(:highscores).find([two['_id'], three['_id']])
42
+ expect(rows.length).to be == 2
43
+ expect(rows[0]['player']).to be == 'Two'
44
+ expect(rows[1]['player']).to be == 'Three'
45
+
46
+ # .all
47
+ all = subject.collection(:highscores).all
48
+ expect(all.length).to be >= 6
49
+
50
+ # .first
51
+ five = subject.collection(:highscores).where(:player => "Five").first
52
+ expect(five['player']).to eq("Five")
53
+
54
+ # .count
55
+ count = subject.collection(:highscores).where(:score.lt => 25).count
56
+ expect(count).to be == 1
57
+
58
+ count = subject.collection(:highscores).where(:score.lte => 25).count
59
+ expect(count).to be == 2
60
+
61
+ count = subject.collection(:highscores).where(:score.between => 11..149).count
62
+ expect(count).to be == 4
63
+
64
+ count = subject.collection(:highscores).where(:player.ne => "One").count
65
+ expect(count).to be == 5
66
+ end
67
+
68
+ end
@@ -0,0 +1,47 @@
1
+ describe Hook::Extensions do
2
+ it "should extend core Ruby classes" do
3
+ gt = :field_gt.gt
4
+ expect(gt.comparation).to eq('>')
5
+ expect(gt.field).to eq(:field_gt)
6
+
7
+ gte = :field_gte.gte
8
+ expect(gte.comparation).to eq('>=')
9
+ expect(gte.field).to eq(:field_gte)
10
+
11
+ lt = :field_lt.lt
12
+ expect(lt.comparation).to eq('<')
13
+ expect(lt.field).to eq(:field_lt)
14
+
15
+ lte = :field_lte.lte
16
+ expect(lte.comparation).to eq('<=')
17
+ expect(lte.field).to eq(:field_lte)
18
+
19
+ ne = :field_ne.ne
20
+ expect(ne.comparation).to eq('!=')
21
+ expect(ne.field).to eq(:field_ne)
22
+
23
+ _in = :field_in.in
24
+ expect(_in.comparation).to eq('in')
25
+ expect(_in.field).to eq(:field_in)
26
+
27
+ not_in = :field_not_in.not_in
28
+ expect(not_in.comparation).to eq('not_in')
29
+ expect(not_in.field).to eq(:field_not_in)
30
+
31
+ nin = :field_nin.nin
32
+ expect(nin.comparation).to eq('not_in')
33
+ expect(nin.field).to eq(:field_nin)
34
+
35
+ like = :field_like.like
36
+ expect(like.comparation).to eq('like')
37
+ expect(like.field).to eq(:field_like)
38
+
39
+ between = :field_between.between
40
+ expect(between.comparation).to eq('between')
41
+ expect(between.field).to eq(:field_between)
42
+
43
+ not_between = :field_not_between.not_between
44
+ expect(not_between.comparation).to eq('not_between')
45
+ expect(not_between.field).to eq(:field_not_between)
46
+ end
47
+ end
@@ -0,0 +1,20 @@
1
+ describe Hook::Keys do
2
+
3
+ subject do
4
+ Hook::Client.instance
5
+ end
6
+
7
+ it "should get and set keys" do
8
+ expect(subject.keys.get(:inexistent)).to be_nil
9
+
10
+ subject.keys.set :numeric, 12345
11
+ expect(subject.keys.get(:numeric)).to be == 12345
12
+
13
+ subject.keys.set :float, 19.99
14
+ expect(subject.keys.get(:float)).to be == 19.99
15
+
16
+ subject.keys.set :string, 'hello there!'
17
+ expect(subject.keys.get(:string)).to be == 'hello there!'
18
+ end
19
+ end
20
+
@@ -0,0 +1,55 @@
1
+ class MyCollection
2
+ include Hook::Model
3
+ field :name
4
+ field :score
5
+ validates_presence_of :score
6
+ end
7
+
8
+ class CustomHighscore
9
+ include Hook::Model
10
+ field :name
11
+ field :score
12
+ end
13
+
14
+ describe Hook::Model do
15
+ it "should respond to activemodel dirty methods" do
16
+ instance = MyCollection.new
17
+ expect(instance.name).to be_nil
18
+ expect(instance.name_changed?).to be == false
19
+
20
+ instance.name = 'Endel'
21
+ expect(instance.name).to be == 'Endel'
22
+ expect(instance.name_changed?).to be == true
23
+
24
+ expect(instance.save).to be == false, "shouldn't save when model has validation errors"
25
+ expect(instance.errors.messages.length).to be == 1
26
+ end
27
+
28
+ it "should set default attributes" do
29
+ instance = MyCollection.new(:name => "Endel", :score => 100)
30
+ expect(instance.name).to be == "Endel"
31
+ expect(instance.score).to be == 100
32
+ expect(instance.changed?).to be == true
33
+ instance.save
34
+ expect(instance.changed?).to be == false
35
+ end
36
+
37
+ it "general methods" do
38
+ instance = MyCollection.create(:name => "Endel", :score => 100)
39
+ expect(instance.name).to be == "Endel"
40
+ expect(instance.score).to be == 100
41
+ expect(instance.changed?).to be == false
42
+ expect(instance.save).to be == false
43
+ end
44
+
45
+ it "should create multiple" do
46
+ rows = CustomHighscore.create([
47
+ {:name => "Somebody", :score => 50},
48
+ {:name => "Anybody", :score => 10},
49
+ ])
50
+ expect(rows.length).to be == 2
51
+ expect(rows[0].name).to be == "Somebody"
52
+ expect(rows[1].name).to be == "Anybody"
53
+ expect(CustomHighscore.delete_all).to be == 2
54
+ end
55
+ end
@@ -0,0 +1,15 @@
1
+ $: << File.expand_path('../lib')
2
+ require 'hook-client'
3
+ require 'logger'
4
+ require 'json'
5
+
6
+ logger = Logger.new(STDOUT)
7
+ app = JSON.parse(File.open('spec/app.json').read)
8
+ app_key = app['keys'].select{|k| k['type'] == 'server' }.first
9
+
10
+ Hook::Client.configure(
11
+ :app_id => app_key['app_id'],
12
+ :key => app_key['key'],
13
+ :endpoint => 'http://hook.dev/public/index.php/'
14
+ # :logger => logger
15
+ )
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hook-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Endel Dreyer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
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
+ - !ruby/object:Gem::Dependency
28
+ name: addressable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: http
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.6.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.6.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.0.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: 2.0.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: activemodel
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: 3.0.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: 3.0.0
83
+ description: Hook Client for Ruby
84
+ email: endel@doubleleft.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - lib/hook-client/auth.rb
90
+ - lib/hook-client/channel/sse.rb
91
+ - lib/hook-client/channel/websocket.rb
92
+ - lib/hook-client/channel.rb
93
+ - lib/hook-client/client.rb
94
+ - lib/hook-client/collection.rb
95
+ - lib/hook-client/extensions/symbol.rb
96
+ - lib/hook-client/extensions.rb
97
+ - lib/hook-client/keys.rb
98
+ - lib/hook-client/model.rb
99
+ - lib/hook-client/version.rb
100
+ - lib/hook-client.rb
101
+ - spec/client_spec.rb
102
+ - spec/collection_spec.rb
103
+ - spec/extensions_spec.rb
104
+ - spec/keys_spec.rb
105
+ - spec/model_spec.rb
106
+ - spec/spec_helper.rb
107
+ - README.md
108
+ - LICENSE
109
+ homepage: http://github.com/doubleleft/hook-ruby
110
+ licenses: []
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.0.6
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: Hook Ruby Client
132
+ test_files: []
133
+ has_rdoc: