freefeed-client 0.1.0
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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +94 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/freefeed.gemspec +34 -0
- data/lib/freefeed/client.rb +90 -0
- data/lib/freefeed/exceptions.rb +27 -0
- data/lib/freefeed/resources/archive.rb +26 -0
- data/lib/freefeed/resources/attachment.rb +11 -0
- data/lib/freefeed/resources/bookmarklet.rb +11 -0
- data/lib/freefeed/resources/comment.rb +36 -0
- data/lib/freefeed/resources/group.rb +61 -0
- data/lib/freefeed/resources/invitation.rb +16 -0
- data/lib/freefeed/resources/notification.rb +11 -0
- data/lib/freefeed/resources/password.rb +16 -0
- data/lib/freefeed/resources/post.rb +61 -0
- data/lib/freefeed/resources/request.rb +11 -0
- data/lib/freefeed/resources/search.rb +11 -0
- data/lib/freefeed/resources/session.rb +11 -0
- data/lib/freefeed/resources/stat.rb +11 -0
- data/lib/freefeed/resources/summary.rb +16 -0
- data/lib/freefeed/resources/timeline.rb +41 -0
- data/lib/freefeed/resources/user.rb +121 -0
- data/lib/freefeed/types/bookmarklet.rb +17 -0
- data/lib/freefeed/types/comment.rb +16 -0
- data/lib/freefeed/types/post.rb +24 -0
- data/lib/freefeed/types.rb +21 -0
- data/lib/freefeed/version.rb +3 -0
- data/lib/freefeed.rb +46 -0
- data/lib/resource_kitling.rb +101 -0
- metadata +207 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 51d600de0410a6c2e6341267d64986af26b39add
|
4
|
+
data.tar.gz: 2c3b31d286d4b5cb477d38389b00306cb973540e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a1aed947a23f1fcc9b9ae852841ecc72688455e0ae499cd504b05a510a823edf3cd0e0a762c8d5cad748673be74d0958824e5c0451628c5a6e4a2469eb81d174
|
7
|
+
data.tar.gz: 2f6299a90a0d4e7e783604d2c7d27f00fcc917ce9ac7f212c6303826231aa31727be25bcac965fe3bb4f134738a86bcd14d8f16a20deca7cd248c8a09a7a0e73
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Ilia Zemskov
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# freefeed-client
|
2
|
+
|
3
|
+
Ruby wrapper for [Freefeed API](https://fetsh.github.io/freefeed-api).
|
4
|
+
|
5
|
+
[](http://badge.fury.io/rb/freefeed-client)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add following line to your Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'freefeed-client'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
```shell
|
18
|
+
$ bundle
|
19
|
+
```
|
20
|
+
|
21
|
+
Or install it system-wide:
|
22
|
+
|
23
|
+
```shell
|
24
|
+
$ gem install freefeed-client
|
25
|
+
```
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
First things first, you need to [obtain a token](https://fetsh.github.io/freefeed-api/#authentication) for your user. Then create your api client like this:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require 'freefeed'
|
33
|
+
|
34
|
+
client = Freefeed::Client.new('yourFreefeedAPIToken')
|
35
|
+
|
36
|
+
post = Freefeed::Types::PostCreate.new(
|
37
|
+
{
|
38
|
+
post: {
|
39
|
+
body: 'Hello World!'
|
40
|
+
},
|
41
|
+
meta: {
|
42
|
+
feeds: ['yourusername']
|
43
|
+
}
|
44
|
+
}
|
45
|
+
)
|
46
|
+
|
47
|
+
post_resource = Freefeed::Post.new(client: client)
|
48
|
+
|
49
|
+
post_resource.create(post)
|
50
|
+
```
|
51
|
+
|
52
|
+
You can skip instantiating resource, but I'm not sure if this is a good practice:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
require 'freefeed'
|
56
|
+
|
57
|
+
client = Freefeed::Client.new('yourFreefeedAPIToken')
|
58
|
+
|
59
|
+
post = Freefeed::Types::PostCreate.new(
|
60
|
+
{
|
61
|
+
post: {
|
62
|
+
body: 'Hello World!'
|
63
|
+
},
|
64
|
+
meta: {
|
65
|
+
feeds: ['yourusername']
|
66
|
+
}
|
67
|
+
}
|
68
|
+
)
|
69
|
+
|
70
|
+
client.posts.create(post)
|
71
|
+
```
|
72
|
+
|
73
|
+
You can even skip instantiating post type, but you will lose some validation:
|
74
|
+
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
require 'freefeed'
|
78
|
+
|
79
|
+
client = Freefeed::Client.new('yourFreefeedAPIToken')
|
80
|
+
|
81
|
+
client.posts.create({post: {body: 'Hello World!'}, meta: {feeds: ['yourusername']}})
|
82
|
+
```
|
83
|
+
|
84
|
+
## Logging
|
85
|
+
|
86
|
+
By default, `freefeed-client` logs everything to STDOUT. You can change this behavior and provide your own logger class with someo ptions. See example below:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
client = Freefeed::Client.new(
|
90
|
+
'yourFreefeedAPIToken',
|
91
|
+
logger: Logger.new('log.txt'),
|
92
|
+
logger_options: {bodies: false, headers: false}
|
93
|
+
)
|
94
|
+
```
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "freefeed"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/freefeed.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'freefeed/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'freefeed-client'
|
8
|
+
spec.version = Freefeed::VERSION
|
9
|
+
spec.authors = ['Ilia Zemskov']
|
10
|
+
spec.email = ['me@fetsh.me']
|
11
|
+
|
12
|
+
spec.summary = 'Ruby wrapper for FreeFeed API.'
|
13
|
+
spec.homepage = 'https://github.com/fetsh/freefeed-client'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = 'bin'
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
|
23
|
+
spec.add_dependency 'faraday'
|
24
|
+
spec.add_dependency 'faraday_middleware'
|
25
|
+
spec.add_dependency 'multi_json'
|
26
|
+
spec.add_dependency 'dry-types'
|
27
|
+
spec.add_dependency 'dry-struct'
|
28
|
+
spec.add_dependency 'activesupport'
|
29
|
+
|
30
|
+
|
31
|
+
spec.add_development_dependency 'bundler', '~> 1.13'
|
32
|
+
spec.add_development_dependency 'rake'
|
33
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
34
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Freefeed
|
2
|
+
class Client
|
3
|
+
HOST = 'freefeed.net'.freeze
|
4
|
+
|
5
|
+
attr_accessor :api_token, :faraday_options, :resources
|
6
|
+
|
7
|
+
def initialize(api_token = nil, faraday_options = {})
|
8
|
+
@api_token = api_token
|
9
|
+
@faraday_options = faraday_options
|
10
|
+
end
|
11
|
+
|
12
|
+
def authenticate(username:, password:)
|
13
|
+
Session.new(client: self)
|
14
|
+
.create(username: username, password: password).tap do |re|
|
15
|
+
@api_token = re.fetch('authToken')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(endpoint, params = {}, headers = {})
|
20
|
+
guard_wrong_endpoint(endpoint)
|
21
|
+
call!(
|
22
|
+
ENDPOINTS[endpoint][:method], path(endpoint),
|
23
|
+
build_options(endpoint, params), headers
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def call!(verb, endpoint, params = {}, headers = {})
|
28
|
+
response = conn.send(
|
29
|
+
verb, endpoint, params, auth_header.merge(headers)
|
30
|
+
)
|
31
|
+
handle_erros(response)
|
32
|
+
prepare_response(response)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def conn
|
38
|
+
@conn ||= Faraday.new(url: "https://#{HOST}") do |faraday|
|
39
|
+
faraday.request :multipart
|
40
|
+
faraday.response(
|
41
|
+
:logger,
|
42
|
+
(faraday_options[:logger] || Logger.new(STDOUT)),
|
43
|
+
(faraday_options[:logger_options] || { bodies: true, headers: true })
|
44
|
+
)
|
45
|
+
faraday.request :json
|
46
|
+
faraday.adapter faraday_options[:adapter] || Faraday.default_adapter
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def guard_wrong_endpoint(endpoint)
|
51
|
+
raise Exceptions::WrongEndpoint unless ENDPOINTS.keys.include?(endpoint)
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_options(endpoint, params)
|
55
|
+
default_params(endpoint).merge(sanitize_params(endpoint, params))
|
56
|
+
end
|
57
|
+
|
58
|
+
def path(endpoint)
|
59
|
+
(endpoint.start_with?('/') ? '' : BASE_PATH) + endpoint.split('#').first
|
60
|
+
end
|
61
|
+
|
62
|
+
def default_params(endpoint)
|
63
|
+
{}.merge(ENDPOINTS[endpoint][:default_params] || {})
|
64
|
+
end
|
65
|
+
|
66
|
+
def sanitize_params(endpoint, params)
|
67
|
+
return {} unless ENDPOINTS[endpoint][:params]
|
68
|
+
params.delete_if do |key, _|
|
69
|
+
!ENDPOINTS[endpoint][:params].include?(key.to_s)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def handle_erros(response)
|
74
|
+
raise(
|
75
|
+
Exceptions::ResponseError.new(response),
|
76
|
+
'Freefeed API has returned the error'
|
77
|
+
) unless response.status == 200
|
78
|
+
end
|
79
|
+
|
80
|
+
def prepare_response(response)
|
81
|
+
MultiJson.load(response.body.to_s)
|
82
|
+
rescue MultiJson::LoadError
|
83
|
+
response.body
|
84
|
+
end
|
85
|
+
|
86
|
+
def auth_header
|
87
|
+
api_token.nil? ? {} : { 'x-authentication-token': api_token }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Freefeed
|
2
|
+
module Exceptions
|
3
|
+
class ResponseError < StandardError
|
4
|
+
attr_reader :response
|
5
|
+
|
6
|
+
def initialize(response)
|
7
|
+
@response = response
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
super + format(' (%s)', data.map { |k, v| %(#{k}: "#{v}") }.join(', '))
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def data
|
17
|
+
@data ||= begin
|
18
|
+
MultiJson.load(response.body)
|
19
|
+
rescue MultiJson::DecodeError
|
20
|
+
{ uri: response.env.url.to_s, errors: response.body.to_s }
|
21
|
+
end.merge(code: response.status)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
class WrongEndpoint < StandardError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Freefeed
|
2
|
+
class Archive < ResourceKitling::Resource
|
3
|
+
actions do
|
4
|
+
action :restoration do
|
5
|
+
verb :post
|
6
|
+
version :v2
|
7
|
+
path '/archives/restoration'
|
8
|
+
end
|
9
|
+
action :activities do
|
10
|
+
verb :put
|
11
|
+
version :v2
|
12
|
+
path '/archives/activities'
|
13
|
+
end
|
14
|
+
action :post_by_old_name do
|
15
|
+
verb :get
|
16
|
+
version :v2
|
17
|
+
path '/archives/post-by-old-name/:name'
|
18
|
+
end
|
19
|
+
action :stats do
|
20
|
+
verb :get
|
21
|
+
version :v2
|
22
|
+
path '/archives-stats'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Freefeed
|
2
|
+
class Comment < ResourceKitling::Resource
|
3
|
+
actions do
|
4
|
+
action :create do
|
5
|
+
verb :post
|
6
|
+
version :v1
|
7
|
+
path '/comments'
|
8
|
+
end
|
9
|
+
action :update do
|
10
|
+
verb :put
|
11
|
+
version :v1
|
12
|
+
path '/comments/:id'
|
13
|
+
end
|
14
|
+
action :destroy do
|
15
|
+
verb :delete
|
16
|
+
version :v1
|
17
|
+
path '/comments/:id'
|
18
|
+
end
|
19
|
+
action :like do
|
20
|
+
verb :post
|
21
|
+
version :v2
|
22
|
+
path '/comments/:id/like'
|
23
|
+
end
|
24
|
+
action :unlike do
|
25
|
+
verb :post
|
26
|
+
version :v2
|
27
|
+
path '/comments/:id/unlike'
|
28
|
+
end
|
29
|
+
action :likes do
|
30
|
+
verb :get
|
31
|
+
version :v2
|
32
|
+
path '/comments/:id/likes'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Freefeed
|
2
|
+
class Group < ResourceKitling::Resource
|
3
|
+
actions do
|
4
|
+
action :create do
|
5
|
+
verb :post
|
6
|
+
version :v1
|
7
|
+
path '/groups'
|
8
|
+
end
|
9
|
+
action :sudo_create do
|
10
|
+
verb :post
|
11
|
+
version :v1
|
12
|
+
path '/groups/sudo'
|
13
|
+
end
|
14
|
+
action :update_profile_picture do
|
15
|
+
verb :post
|
16
|
+
version :v1
|
17
|
+
path '/groups/:name/updateProfilePicture'
|
18
|
+
end
|
19
|
+
action :admin do
|
20
|
+
verb :post
|
21
|
+
version :v1
|
22
|
+
path '/groups/:name/subscribers/:username/admin'
|
23
|
+
end
|
24
|
+
action :unadmin do
|
25
|
+
verb :post
|
26
|
+
version :v1
|
27
|
+
path '/groups/:name/subscribers/:username/unadmin'
|
28
|
+
end
|
29
|
+
action :send_request do
|
30
|
+
verb :post
|
31
|
+
version :v1
|
32
|
+
path '/groups/:name/sendRequest'
|
33
|
+
end
|
34
|
+
action :accept_request do
|
35
|
+
verb :post
|
36
|
+
version :v1
|
37
|
+
path '/groups/:name/acceptRequest/:username'
|
38
|
+
end
|
39
|
+
action :reject_request do
|
40
|
+
verb :post
|
41
|
+
version :v1
|
42
|
+
path '/groups/:name/rejectRequest/:username'
|
43
|
+
end
|
44
|
+
action :unsubscribe_from_group do
|
45
|
+
verb :post
|
46
|
+
version :v1
|
47
|
+
path '/groups/:name/unsubscribeFromGroup/:username'
|
48
|
+
end
|
49
|
+
action :manage do
|
50
|
+
verb :get
|
51
|
+
version :v2
|
52
|
+
path '/managedGroups'
|
53
|
+
end
|
54
|
+
action :all do
|
55
|
+
verb :get
|
56
|
+
version :v2
|
57
|
+
path '/allGroups'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Freefeed
|
2
|
+
class Invitation < ResourceKitling::Resource
|
3
|
+
actions do
|
4
|
+
action :create do
|
5
|
+
verb :post
|
6
|
+
version :v2
|
7
|
+
path '/invitations'
|
8
|
+
end
|
9
|
+
action :get do
|
10
|
+
verb :get
|
11
|
+
version :v2
|
12
|
+
path '/invitations/:id'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Freefeed
|
2
|
+
class Password < ResourceKitling::Resource
|
3
|
+
actions do
|
4
|
+
action :create do
|
5
|
+
verb :post
|
6
|
+
version :v1
|
7
|
+
path '/passwords'
|
8
|
+
end
|
9
|
+
action :update do
|
10
|
+
verb :put
|
11
|
+
version :v1
|
12
|
+
path '/passwords/:token'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Freefeed
|
2
|
+
class Post < ResourceKitling::Resource
|
3
|
+
actions do
|
4
|
+
action :create do
|
5
|
+
verb :post
|
6
|
+
version :v1
|
7
|
+
path '/posts'
|
8
|
+
end
|
9
|
+
action :get do
|
10
|
+
verb :get
|
11
|
+
version :v2
|
12
|
+
path '/posts/:id'
|
13
|
+
end
|
14
|
+
action :update do
|
15
|
+
verb :put
|
16
|
+
version :v1
|
17
|
+
path '/posts/:id'
|
18
|
+
end
|
19
|
+
action :destroy do
|
20
|
+
verb :delete
|
21
|
+
version :v1
|
22
|
+
path '/posts/:id'
|
23
|
+
end
|
24
|
+
action :like do
|
25
|
+
verb :post
|
26
|
+
version :v1
|
27
|
+
path '/posts/:id/like'
|
28
|
+
end
|
29
|
+
action :unlike do
|
30
|
+
verb :post
|
31
|
+
version :v1
|
32
|
+
path '/posts/:id/unlike'
|
33
|
+
end
|
34
|
+
action :hide do
|
35
|
+
verb :post
|
36
|
+
version :v1
|
37
|
+
path '/posts/:id/hide'
|
38
|
+
end
|
39
|
+
action :unhide do
|
40
|
+
verb :post
|
41
|
+
version :v1
|
42
|
+
path '/posts/:id/unhide'
|
43
|
+
end
|
44
|
+
action :disable_comments do
|
45
|
+
verb :post
|
46
|
+
version :v1
|
47
|
+
path '/posts/:id/disableComments'
|
48
|
+
end
|
49
|
+
action :enable_comments do
|
50
|
+
verb :post
|
51
|
+
version :v1
|
52
|
+
path '/posts/:id/enableComments'
|
53
|
+
end
|
54
|
+
action :opengraph do
|
55
|
+
verb :get
|
56
|
+
version :v2
|
57
|
+
path '/posts-opengraph/:id'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Freefeed
|
2
|
+
class Summary < ResourceKitling::Resource
|
3
|
+
actions do
|
4
|
+
action :general do
|
5
|
+
verb :get
|
6
|
+
version :v2
|
7
|
+
path '/summary/:days'
|
8
|
+
end
|
9
|
+
action :by_user do
|
10
|
+
verb :get
|
11
|
+
version :v2
|
12
|
+
path '/summary/:username/:days'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Freefeed
|
2
|
+
class Timeline < ResourceKitling::Resource
|
3
|
+
actions do
|
4
|
+
action :bestof do
|
5
|
+
verb :get
|
6
|
+
version :v2
|
7
|
+
path '/bestof'
|
8
|
+
end
|
9
|
+
action :home do
|
10
|
+
verb :get
|
11
|
+
version :v2
|
12
|
+
path '/timelines/home'
|
13
|
+
end
|
14
|
+
action :discussions do
|
15
|
+
verb :get
|
16
|
+
version :v2
|
17
|
+
path '/timelines/filter/discussions'
|
18
|
+
end
|
19
|
+
action :directs do
|
20
|
+
verb :get
|
21
|
+
version :v2
|
22
|
+
path '/timelines/filter/directs'
|
23
|
+
end
|
24
|
+
action :posts do
|
25
|
+
verb :get
|
26
|
+
version :v2
|
27
|
+
path '/timelines/:username'
|
28
|
+
end
|
29
|
+
action :likes do
|
30
|
+
verb :get
|
31
|
+
version :v2
|
32
|
+
path '/timelines/:username/likes'
|
33
|
+
end
|
34
|
+
action :comments do
|
35
|
+
verb :get
|
36
|
+
version :v2
|
37
|
+
path '/timelines/:username/comments'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Freefeed
|
2
|
+
class User < ResourceKitling::Resource
|
3
|
+
actions do
|
4
|
+
action :create do
|
5
|
+
verb :post
|
6
|
+
version :v1
|
7
|
+
path '/users'
|
8
|
+
end
|
9
|
+
action :sudo_create do
|
10
|
+
verb :post
|
11
|
+
version :v1
|
12
|
+
path '/users/sudo'
|
13
|
+
end
|
14
|
+
action :send_request do
|
15
|
+
verb :post
|
16
|
+
version :v1
|
17
|
+
path '/users/:username/sendRequest'
|
18
|
+
end
|
19
|
+
action :revoke_request do
|
20
|
+
verb :post
|
21
|
+
version :v2
|
22
|
+
path '/requests/:username/revoke'
|
23
|
+
end
|
24
|
+
action :accept_request do
|
25
|
+
verb :post
|
26
|
+
version :v1
|
27
|
+
path '/users/acceptRequest/:username'
|
28
|
+
end
|
29
|
+
action :reject_request do
|
30
|
+
verb :post
|
31
|
+
version :v1
|
32
|
+
path '/users/rejectRequest/:username'
|
33
|
+
end
|
34
|
+
action :unsubscribe_from_me do
|
35
|
+
verb :post
|
36
|
+
version :v1
|
37
|
+
path '/users/:username/unsubscribeFromMe'
|
38
|
+
end
|
39
|
+
action :show do
|
40
|
+
verb :get
|
41
|
+
version :v1
|
42
|
+
path '/users/:username'
|
43
|
+
end
|
44
|
+
action :update_password do
|
45
|
+
verb :put
|
46
|
+
version :v1
|
47
|
+
path '/users/updatePassword'
|
48
|
+
end
|
49
|
+
action :update_profile_picture do
|
50
|
+
verb :post
|
51
|
+
version :v1
|
52
|
+
path '/users/updateProfilePicture'
|
53
|
+
end
|
54
|
+
action :update do
|
55
|
+
verb :put
|
56
|
+
version :v1
|
57
|
+
path '/users/:id'
|
58
|
+
end
|
59
|
+
action :ban do
|
60
|
+
verb :post
|
61
|
+
version :v1
|
62
|
+
path '/users/:username/ban'
|
63
|
+
end
|
64
|
+
action :unban do
|
65
|
+
verb :post
|
66
|
+
version :v1
|
67
|
+
path '/users/:username/unban'
|
68
|
+
end
|
69
|
+
action :subscribe do
|
70
|
+
verb :post
|
71
|
+
version :v1
|
72
|
+
path '/users/:username/subscribe'
|
73
|
+
end
|
74
|
+
action :unsubscribe do
|
75
|
+
verb :post
|
76
|
+
version :v1
|
77
|
+
path '/users/:username/unsubscribe'
|
78
|
+
end
|
79
|
+
action :subscribers do
|
80
|
+
verb :get
|
81
|
+
version :v1
|
82
|
+
path '/users/:username/subscribers'
|
83
|
+
end
|
84
|
+
action :subscriptions do
|
85
|
+
verb :get
|
86
|
+
version :v1
|
87
|
+
path '/users/:username/subscriptions'
|
88
|
+
end
|
89
|
+
action :blocked do
|
90
|
+
verb :get
|
91
|
+
version :v2
|
92
|
+
path '/users/blockedByMe'
|
93
|
+
end
|
94
|
+
action :unread_directs_number do
|
95
|
+
verb :get
|
96
|
+
version :v2
|
97
|
+
path '/users/getUnreadDirectsNumber'
|
98
|
+
end
|
99
|
+
action :unread_notifications_number do
|
100
|
+
verb :get
|
101
|
+
version :v2
|
102
|
+
path '/users/getUnreadNotificationsNumber'
|
103
|
+
end
|
104
|
+
action :mark_all_directs_as_read do
|
105
|
+
verb :get
|
106
|
+
version :v2
|
107
|
+
path '/users/markAllDirectsAsRead'
|
108
|
+
end
|
109
|
+
action :mark_all_notifications_as_read do
|
110
|
+
verb :post
|
111
|
+
version :v2
|
112
|
+
path '/users/markAllNotificationsAsRead'
|
113
|
+
end
|
114
|
+
action :whoami do
|
115
|
+
verb :get
|
116
|
+
version :v2
|
117
|
+
path '/users/whoami'
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'dry-types'
|
2
|
+
require 'dry-struct'
|
3
|
+
module Freefeed
|
4
|
+
module Types
|
5
|
+
class Bookmarklet < Dry::Struct
|
6
|
+
attribute :title, Types::Body
|
7
|
+
attribute :comment, Types::Strict::String.meta(omittable: true)
|
8
|
+
attribute :image, Types::Strict::String.meta(omittable: true)
|
9
|
+
attribute :images, Types::Strict::Array.of(
|
10
|
+
Types::Strict::String
|
11
|
+
).meta(omittable: true)
|
12
|
+
attribute :meta, Types::Hash.schema(
|
13
|
+
feeds: Types::AccountName | Types::Feeds
|
14
|
+
).meta(omittable: true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'dry-types'
|
2
|
+
require 'dry-struct'
|
3
|
+
module Freefeed
|
4
|
+
module Types
|
5
|
+
class CommentCreate < Dry::Struct
|
6
|
+
attribute :comment, Types::Hash.schema(
|
7
|
+
body: Types::Body,
|
8
|
+
postId: Types::UID
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
class CommentUpdate < Dry::Struct
|
13
|
+
attribute :comment, Types::Hash.schema(body: Types::Body)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'dry-types'
|
2
|
+
require 'dry-struct'
|
3
|
+
module Freefeed
|
4
|
+
module Types
|
5
|
+
class PostCreate < Dry::Struct
|
6
|
+
attribute :post, Types::Hash.schema(
|
7
|
+
body: Types::Body,
|
8
|
+
attachments: Types::Attachments.meta(omittable: true)
|
9
|
+
)
|
10
|
+
attribute :meta, Types::Hash.schema(
|
11
|
+
commentsDisabled: Types::Strict::Bool.default(false),
|
12
|
+
feeds: Types::AccountName | Types::Feeds
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
class PostUpdate < Dry::Struct
|
17
|
+
attribute :post, Types::Hash.schema(
|
18
|
+
body: Types::Body.meta(omittable: true),
|
19
|
+
attachments: Types::Attachments.meta(omittable: true),
|
20
|
+
feeds: Types::Feeds.meta(omittable: true)
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'dry-types'
|
2
|
+
require 'dry-struct'
|
3
|
+
module Freefeed
|
4
|
+
module Types
|
5
|
+
include Dry::Types.module
|
6
|
+
|
7
|
+
Body = Types::Strict::String.constrained(min_size: 1, format: %r{\S+})
|
8
|
+
UID = Types::Strict::String.constrained(
|
9
|
+
format: %r{^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$}
|
10
|
+
)
|
11
|
+
UserName = Types::Strict::String.constrained(
|
12
|
+
min_size: 3, max_size: 25, format: %r{^[A-Za-z0-9]+$}
|
13
|
+
)
|
14
|
+
GroupName = Types::Strict::String.constrained(
|
15
|
+
min_size: 3, max_size: 25, format: %r{^[A-Za-z0-9]+(-[a-zA-Z0-9]+)*$}
|
16
|
+
)
|
17
|
+
AccountName = UserName | GroupName
|
18
|
+
Attachments = Types::Strict::Array.of(UID)
|
19
|
+
Feeds = Types::Strict::Array.of(AccountName)
|
20
|
+
end
|
21
|
+
end
|
data/lib/freefeed.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'logger'
|
4
|
+
require 'multi_json'
|
5
|
+
require 'resource_kitling'
|
6
|
+
require 'freefeed/version'
|
7
|
+
require 'freefeed/exceptions'
|
8
|
+
require 'freefeed/client'
|
9
|
+
require 'active_support/inflector'
|
10
|
+
|
11
|
+
require 'freefeed/resources/archive'
|
12
|
+
require 'freefeed/resources/attachment'
|
13
|
+
require 'freefeed/resources/bookmarklet'
|
14
|
+
require 'freefeed/resources/comment'
|
15
|
+
require 'freefeed/resources/group'
|
16
|
+
require 'freefeed/resources/invitation'
|
17
|
+
require 'freefeed/resources/notification'
|
18
|
+
require 'freefeed/resources/password'
|
19
|
+
require 'freefeed/resources/post'
|
20
|
+
require 'freefeed/resources/request'
|
21
|
+
require 'freefeed/resources/search'
|
22
|
+
require 'freefeed/resources/session'
|
23
|
+
require 'freefeed/resources/stat'
|
24
|
+
require 'freefeed/resources/summary'
|
25
|
+
require 'freefeed/resources/timeline'
|
26
|
+
require 'freefeed/resources/user'
|
27
|
+
|
28
|
+
require 'freefeed/types'
|
29
|
+
require 'freefeed/types/bookmarklet'
|
30
|
+
require 'freefeed/types/comment'
|
31
|
+
require 'freefeed/types/post'
|
32
|
+
|
33
|
+
ResourceKitling::Resource.subclasses.each do |sc|
|
34
|
+
mn = sc.to_s.downcase.split('::').last.pluralize
|
35
|
+
if Freefeed::Client.method_defined?(mn)
|
36
|
+
raise(
|
37
|
+
ArgumentError,
|
38
|
+
"Method '#{mn}' is already defined on Freefeed::Client"
|
39
|
+
)
|
40
|
+
end
|
41
|
+
Freefeed::Client.send(:define_method, mn) do
|
42
|
+
instance_variable_get("@#{mn}") || instance_variable_set(
|
43
|
+
"@#{mn}", sc.new(client: self)
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module ResourceKitling
|
2
|
+
require 'forwardable'
|
3
|
+
class ActionCollection
|
4
|
+
extend Forwardable
|
5
|
+
def_delegators :@collection, :find, :<<, :each, :include?
|
6
|
+
def initialize
|
7
|
+
@collection = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def action(name, &block)
|
11
|
+
action = Action.new(name)
|
12
|
+
action.instance_eval(&block) if block_given?
|
13
|
+
action.tap { |a| @collection << a }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Action
|
18
|
+
attr_reader :name
|
19
|
+
|
20
|
+
def initialize(name)
|
21
|
+
@name = name
|
22
|
+
@verb = :get
|
23
|
+
@version = 'v1'
|
24
|
+
@path = path
|
25
|
+
end
|
26
|
+
|
27
|
+
def verb(v = nil)
|
28
|
+
@verb = v if v
|
29
|
+
@verb
|
30
|
+
end
|
31
|
+
|
32
|
+
def version(v = nil)
|
33
|
+
@version = v if v
|
34
|
+
@version
|
35
|
+
end
|
36
|
+
|
37
|
+
def path(path = nil, &block)
|
38
|
+
raise "You must pass either a block or a string for paths" if path and block_given?
|
39
|
+
@path = path if path
|
40
|
+
@path = block if block_given?
|
41
|
+
@path
|
42
|
+
end
|
43
|
+
|
44
|
+
def generated_path(values = {})
|
45
|
+
values.inject("/#{version}/#{path}") do |np, (key, value)|
|
46
|
+
np.gsub(":#{key}", value.to_s)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
class Resource
|
51
|
+
class << self
|
52
|
+
attr_accessor :_actions
|
53
|
+
attr_reader :subclasses
|
54
|
+
def inherited(subclass)
|
55
|
+
superclass.inherited(subclass) if superclass.respond_to?(:inherited)
|
56
|
+
@subclasses ||= []
|
57
|
+
@subclasses << subclass
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.actions(&block)
|
62
|
+
self._actions ||= ActionCollection.new
|
63
|
+
if block_given?
|
64
|
+
self._actions.instance_eval(&block)
|
65
|
+
# MethodFactory.construct(self, self._actions)
|
66
|
+
self._actions.each do |action|
|
67
|
+
if method_defined?(action.name)
|
68
|
+
raise(
|
69
|
+
ArgumentError,
|
70
|
+
"Action '#{action.name}' is already defined on `#{self}`"
|
71
|
+
)
|
72
|
+
end
|
73
|
+
method_block = method_for_action(action)
|
74
|
+
send(:define_method, action.name, &method_block)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
self._actions
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.method_for_action(action)
|
81
|
+
Proc.new do |*args|
|
82
|
+
pathopts = action.path.include?(':') ? args.shift : {}
|
83
|
+
payload = args.shift
|
84
|
+
payload = payload.to_h if payload.respond_to?(:to_h)
|
85
|
+
client.call!(
|
86
|
+
action.verb, action.generated_path(pathopts), payload, *args
|
87
|
+
)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def actions
|
92
|
+
self.class.actions
|
93
|
+
end
|
94
|
+
|
95
|
+
attr_reader :client
|
96
|
+
|
97
|
+
def initialize(client: nil)
|
98
|
+
@client = client
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
metadata
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: freefeed-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ilia Zemskov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-10-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
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: faraday_middleware
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: 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: dry-types
|
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: dry-struct
|
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: activesupport
|
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
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: bundler
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.13'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.13'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
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
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '3.0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '3.0'
|
139
|
+
description:
|
140
|
+
email:
|
141
|
+
- me@fetsh.me
|
142
|
+
executables:
|
143
|
+
- console
|
144
|
+
- setup
|
145
|
+
extensions: []
|
146
|
+
extra_rdoc_files: []
|
147
|
+
files:
|
148
|
+
- ".gitignore"
|
149
|
+
- ".rspec"
|
150
|
+
- ".travis.yml"
|
151
|
+
- Gemfile
|
152
|
+
- LICENSE.txt
|
153
|
+
- README.md
|
154
|
+
- Rakefile
|
155
|
+
- bin/console
|
156
|
+
- bin/setup
|
157
|
+
- freefeed.gemspec
|
158
|
+
- lib/freefeed.rb
|
159
|
+
- lib/freefeed/client.rb
|
160
|
+
- lib/freefeed/exceptions.rb
|
161
|
+
- lib/freefeed/resources/archive.rb
|
162
|
+
- lib/freefeed/resources/attachment.rb
|
163
|
+
- lib/freefeed/resources/bookmarklet.rb
|
164
|
+
- lib/freefeed/resources/comment.rb
|
165
|
+
- lib/freefeed/resources/group.rb
|
166
|
+
- lib/freefeed/resources/invitation.rb
|
167
|
+
- lib/freefeed/resources/notification.rb
|
168
|
+
- lib/freefeed/resources/password.rb
|
169
|
+
- lib/freefeed/resources/post.rb
|
170
|
+
- lib/freefeed/resources/request.rb
|
171
|
+
- lib/freefeed/resources/search.rb
|
172
|
+
- lib/freefeed/resources/session.rb
|
173
|
+
- lib/freefeed/resources/stat.rb
|
174
|
+
- lib/freefeed/resources/summary.rb
|
175
|
+
- lib/freefeed/resources/timeline.rb
|
176
|
+
- lib/freefeed/resources/user.rb
|
177
|
+
- lib/freefeed/types.rb
|
178
|
+
- lib/freefeed/types/bookmarklet.rb
|
179
|
+
- lib/freefeed/types/comment.rb
|
180
|
+
- lib/freefeed/types/post.rb
|
181
|
+
- lib/freefeed/version.rb
|
182
|
+
- lib/resource_kitling.rb
|
183
|
+
homepage: https://github.com/fetsh/freefeed-client
|
184
|
+
licenses:
|
185
|
+
- MIT
|
186
|
+
metadata: {}
|
187
|
+
post_install_message:
|
188
|
+
rdoc_options: []
|
189
|
+
require_paths:
|
190
|
+
- lib
|
191
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
192
|
+
requirements:
|
193
|
+
- - ">="
|
194
|
+
- !ruby/object:Gem::Version
|
195
|
+
version: '0'
|
196
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '0'
|
201
|
+
requirements: []
|
202
|
+
rubyforge_project:
|
203
|
+
rubygems_version: 2.5.2.1
|
204
|
+
signing_key:
|
205
|
+
specification_version: 4
|
206
|
+
summary: Ruby wrapper for FreeFeed API.
|
207
|
+
test_files: []
|