trefoil 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: adc7d1dd5401c32dd327285a1ce3e19abcfadad43ccc6a0b77cd8fb84ef10fce
4
+ data.tar.gz: 4fe016b919392ce8b3c6cab0869f6ad8426a2b58926493411fc8a2e681a5d643
5
+ SHA512:
6
+ metadata.gz: eb556fef835e6de55617d0ebe1a5208a8823caa847ea72d7cef592604092db83d4c6dcefc3bdb79921a5556f08e8f5c7fa6fc5d5e69466c169a84b5ef4b94c6f
7
+ data.tar.gz: f4e10541ee9e963e4bd80dfc973d08117fbc033e939945814d074747b188f64f63eb5d1f2ea9f50fc5d2643673c415ae2062d257fa5d6023d66040e81ff30739
data/.codeclimate.yml ADDED
@@ -0,0 +1,3 @@
1
+ plugins:
2
+ rubocop:
3
+ enabled: true
data/.gitattributes ADDED
@@ -0,0 +1,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
data/.gitignore ADDED
@@ -0,0 +1,50 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper -I lib
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ Metrics:
2
+ Enabled: false
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.3
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ script:
3
+ - rake
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec name: 'trefoil'
data/Gemfile.lock ADDED
@@ -0,0 +1,78 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ trefoil (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.6.0)
10
+ public_suffix (>= 2.0.2, < 4.0)
11
+ ast (2.4.0)
12
+ crack (0.4.3)
13
+ safe_yaml (~> 1.0.0)
14
+ diff-lcs (1.3)
15
+ docile (1.3.1)
16
+ hashdiff (0.3.8)
17
+ jaro_winkler (1.5.2)
18
+ json (2.2.0)
19
+ parallel (1.14.0)
20
+ parser (2.6.0.0)
21
+ ast (~> 2.4.0)
22
+ powerpack (0.1.2)
23
+ psych (3.1.0)
24
+ public_suffix (3.0.3)
25
+ rainbow (3.0.0)
26
+ rake (12.3.2)
27
+ redcarpet (3.4.0)
28
+ rspec (3.8.0)
29
+ rspec-core (~> 3.8.0)
30
+ rspec-expectations (~> 3.8.0)
31
+ rspec-mocks (~> 3.8.0)
32
+ rspec-core (3.8.0)
33
+ rspec-support (~> 3.8.0)
34
+ rspec-expectations (3.8.2)
35
+ diff-lcs (>= 1.2.0, < 2.0)
36
+ rspec-support (~> 3.8.0)
37
+ rspec-mocks (3.8.0)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.8.0)
40
+ rspec-support (3.8.0)
41
+ rubocop (0.65.0)
42
+ jaro_winkler (~> 1.5.1)
43
+ parallel (~> 1.10)
44
+ parser (>= 2.5, != 2.5.1.1)
45
+ powerpack (~> 0.1)
46
+ psych (>= 3.1.0)
47
+ rainbow (>= 2.2.2, < 4.0)
48
+ ruby-progressbar (~> 1.7)
49
+ unicode-display_width (~> 1.4.0)
50
+ ruby-progressbar (1.10.0)
51
+ safe_yaml (1.0.5)
52
+ simplecov (0.16.1)
53
+ docile (~> 1.1)
54
+ json (>= 1.8, < 3)
55
+ simplecov-html (~> 0.10.0)
56
+ simplecov-html (0.10.2)
57
+ unicode-display_width (1.4.1)
58
+ webmock (3.4.2)
59
+ addressable (>= 2.3.6)
60
+ crack (>= 0.3.2)
61
+ hashdiff
62
+ yard (0.9.18)
63
+
64
+ PLATFORMS
65
+ ruby
66
+
67
+ DEPENDENCIES
68
+ rake (~> 12.0)
69
+ redcarpet (~> 3.4.0)
70
+ rspec (~> 3.8.0)
71
+ rubocop (~> 0.65)
72
+ simplecov (~> 0.16.0)
73
+ trefoil!
74
+ webmock (~> 3.4.0)
75
+ yard (~> 0.9.9)
76
+
77
+ BUNDLED WITH
78
+ 2.0.1
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Matthew Carey
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_helper'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+ require 'yard'
7
+
8
+ namespace :test do
9
+ desc 'Run specs'
10
+ RSpec::Core::RakeTask.new(:spec) do |t|
11
+ t.verbose = false
12
+ end
13
+
14
+ desc 'Run rubocop'
15
+ RuboCop::RakeTask.new(:rubocop)
16
+
17
+ task all: %i[spec rubocop]
18
+ end
19
+
20
+ task test: 'test:all'
21
+
22
+ desc 'Generate yard docs'
23
+ YARD::Rake::YardocTask.new do |t|
24
+ t.files = ['lib/**/*.rb']
25
+ end
26
+
27
+ desc 'alias for `yard`'
28
+ task docs: :yard
29
+
30
+ task default: :test
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Trefoil
4
+ # Class representing a board. Used for requesting threads.
5
+ # A list of all ids can be found with `#threads`.
6
+ # An array of all active Threads can be obtained through `#catalog`.
7
+ # A list of archived thread ids can be found with `#archive.`
8
+ class Board
9
+ # @return [String] The name of the board being referenced.
10
+ attr_reader :name
11
+
12
+ def initialize(client, name)
13
+ @client = client
14
+ @name = name
15
+ @catalog = []
16
+ end
17
+
18
+ # Get info about this board. Keys based on `/boards.json`
19
+ # @param key [Symbol] The key to the desired data.
20
+ # @return [String, Integer, Hash<Symbol => Integer>, nil]
21
+ def [](key)
22
+ @client.send(:cache_boards) if board_cache.empty?
23
+ return nil unless board_cache[name]
24
+
25
+ board_cache[name][key]
26
+ end
27
+
28
+ # Whether or not this board is archived
29
+ # @return [true, false]
30
+ def archived?
31
+ self[:archived] == 1
32
+ end
33
+
34
+ # Whether or not this board is marked as not safe for work
35
+ # @return [true, false]
36
+ def nsfw?
37
+ self[:ws_board].zero?
38
+ end
39
+
40
+ # Gets a new thread by id.
41
+ # @param id [Integer] Thread id.
42
+ def thread(id)
43
+ Thread.new(client, self, id)
44
+ end
45
+
46
+ # Get a hash of threads and their last modified time
47
+ # @return [Hash<Integer => Integer>] A hash with thread ids as keys and their
48
+ # last modified time as the corresponding value.
49
+ def threads
50
+ thread_list = {}
51
+ pages = @client.get("#{name}/threads.json")
52
+ pages.each do |page|
53
+ page[:threads].each do |thread|
54
+ thread_list[thread[:no]] = thread[:last_modified]
55
+ end
56
+ end
57
+
58
+ thread_list
59
+ end
60
+
61
+ # Retrive an array of archived thread ids.
62
+ # @return [Array<Integer>]
63
+ def archive
64
+ @client.get("#{name}/archive.json")
65
+ end
66
+
67
+ # Return a list of all active ops
68
+ # @return [Array<Hash<Symbol => Integer, String>>]
69
+ def catalog
70
+ return @catalog unless @catalog.empty?
71
+
72
+ update_catalog
73
+ @catalog
74
+ end
75
+
76
+ # Update the catalog with new ops
77
+ def update_catalog
78
+ @catalog = []
79
+ pages = @client.get("#{name}/catalog.json")
80
+ pages.each do |page|
81
+ page[:threads].each do |op|
82
+ @catalog << op
83
+ end
84
+ end
85
+ end
86
+
87
+ # Link to a board's custom spoiler
88
+ # @param int [Integer, nil] the custom spoiler id to use pics one randomly if left nil.
89
+ # @return [String, nil] The url to a spoiler, or nil if this board does not have custom spoilers.
90
+ def custom_spoiler(int = nil)
91
+ return nil unless self[:custom_spoilers]
92
+
93
+ spoiler_id = int || rand(self[:custom_spoilers]) + 1
94
+
95
+ "http://s.4cdn.org/image/spoiler-#{name}#{spoiler_id}.png"
96
+ end
97
+
98
+ private
99
+
100
+ # Proxy method for accessing the client's board cache
101
+ # @return [Hash<String => Hash<Symbol => String, Integer, Hash<String => Integer>>>]
102
+ def board_cache
103
+ @client.instance_variable_get(:@board_cache)
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'net/http'
5
+
6
+ module Trefoil
7
+ # Client used for making requests to the API. Respects API rules for rate limiting
8
+ # and thread watching.
9
+ class Client
10
+ BASE_URL = 'a.4cdn.org'
11
+
12
+ # Initialize with a last_request time 1 second prior to present
13
+ # so that we can make requests right away
14
+ def initialize
15
+ @last_request = Time.now - 1
16
+ @mutex = Mutex.new
17
+ @board_cache = {}
18
+ end
19
+
20
+ # Get a JSON parsed response from a given endpoint. Limited to 1 request
21
+ # per second in compliance with API rules.
22
+ # @param endpoint [String] The endpoint to request data from.
23
+ # @return [Hash<Symbol => String, Fixnum>] The returned data structure
24
+ def get(endpoint)
25
+ @mutex.synchronize do
26
+ sleep time_until_available if must_wait?
27
+ resp = Net::HTTP.get_response(BASE_URL, format_endpoint(endpoint))
28
+ @last_request = Time.now
29
+ case resp.code.to_i
30
+ when 200
31
+ JSON.parse(resp.body, symbolize_names: true)
32
+ when 400..500
33
+ raise 'Error making a request' # TODO: Better error handling
34
+ else
35
+ raise 'Unhandled status code' # TODO: better code handling
36
+ end
37
+ end
38
+ end
39
+
40
+ # Get a board object based on its name
41
+ # @param board_name [String]
42
+ def board(board_name)
43
+ Board.new(self, board_name)
44
+ end
45
+
46
+ private
47
+
48
+ # Adds leading '/' to requests
49
+ # @param endpoint [String] The endpoint being formatted
50
+ # @return [String] `endpoint` with leading `/` added if needed
51
+ def format_endpoint(endpoint)
52
+ return endpoint if endpoint[0] == '/'
53
+
54
+ '/' + endpoint
55
+ end
56
+
57
+ # Amount of time before the mutex is freed for the next request
58
+ # @return [Fixnum, Float] Time remaining until the next request can be made
59
+ def time_until_available
60
+ (@last_request + 1) - Time.now
61
+ end
62
+
63
+ # Whether we must wait to make a request
64
+ # @return [true, false] Whether we need to wait or not
65
+ def must_wait?
66
+ time_until_available.positive?
67
+ end
68
+
69
+ # Cache boards from `/boards.json`. Called when accessing `Board#[]` for
70
+ # the first time. Effects last request time.
71
+ def cache_boards
72
+ boards = get('boards.json')
73
+ boards[:boards].each do |board_obj|
74
+ @board_cache[board_obj[:board]] = board_obj
75
+ end
76
+
77
+ @board_cache[:troll_flags] = boards[:troll_flags]
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'trefoil/board'
4
+
5
+ module Trefoil
6
+ # A class representing an Image using data from a post object.
7
+ class Image
8
+ # @return [Integer] Renamed filename (UNIX timestamp + miliseconds)
9
+ attr_reader :tim
10
+
11
+ # @return [String] Original filename of this image
12
+ attr_reader :filename
13
+
14
+ # @return [String] File extension of the fullsize image.
15
+ attr_reader :ext
16
+
17
+ # @return [Integer] Filesize of the fullsize image.
18
+ attr_reader :fsize
19
+
20
+ # @return [String] MD5 hash of fullsize image.
21
+ attr_reader :md5
22
+
23
+ # @return [Integer] Width of fullsize image.
24
+ attr_reader :w
25
+
26
+ # @return [Integer] Height of fullsize image.
27
+ attr_reader :h
28
+
29
+ # @return [Integer] Width of thumbnail.
30
+ attr_reader :tn_w
31
+
32
+ # @return [Integer] Height of thumbnail.
33
+ attr_reader :tn_h
34
+
35
+ # @return [0, 1, nil] Whether this image is deleted. Use `#image?` for a boolean representation.
36
+ attr_reader :filedeleted
37
+
38
+ # @return [0, 1, nil] Whether this image is a spoiler. Use `#spoiler?` for a boolean representation.
39
+ attr_reader :spoiler
40
+
41
+ # @return [String] The name of the board this image is associated with.
42
+ attr_reader :board_name
43
+
44
+ # Create a new image object. Intended for internal use.
45
+ # @param data [Hash<Symbol => Integer, String] Data from a post object to extrapolate info from.
46
+ # @param board [Board, String] The board, or board name, associated with the post this image is from.
47
+ def initialize(data, board)
48
+ expand_data(data)
49
+ @board_name = board.is_a?(Board) ? board[:name] : board
50
+ end
51
+
52
+ # The url to the full size image.
53
+ # @return [String] url to the fullsize version of this image.
54
+ def url
55
+ "http://i.4cdn.org/#{board_name}/#{tim}#{ext}"
56
+ end
57
+
58
+ # The url to the thumbnail of this image.
59
+ # @return [String] url to the thumbnail of this image.
60
+ def thumbnail_url
61
+ "http://i.4cdn.org/#{board_name}/#{tim}s.jpg"
62
+ end
63
+
64
+ # Convenience abstraction for determining if this file was deleted.
65
+ # @return [true, false] Whether this file was deleted.
66
+ def file_deleted?
67
+ filedeleted == 1
68
+ end
69
+
70
+ # Convenience abstraction for determining if this file is a spoiler.
71
+ # @return [true, false] Whether this file is a spoiler.
72
+ def spoiler?
73
+ spoiler == 1
74
+ end
75
+
76
+ private
77
+
78
+ # Move desired values from post data into instance variables.
79
+ # @param data [Hash<Symbol => Integer, String] Data from a Post object.
80
+ def expand_data(data)
81
+ %i[tim filename ext fsize md5 w h tn_w tn_h filedeleted spoiler].each do |sym|
82
+ instance_variable_set("@#{sym}", data[sym])
83
+ end
84
+ end
85
+ end
86
+ end
File without changes
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Trefoil
4
+ # Represents a `post` object.
5
+ # Post object data varies greatly based on board, content, and whether it is an OP.
6
+ # Possible fields are available for viewing in the (API documentation)[https://github.com/4chan/4chan-API#posts-object]
7
+ class Post
8
+ # Intended for internal use
9
+ def initialize(client, board, thread, data)
10
+ @client = client
11
+ @board = board
12
+ @thread = thread
13
+ @data = data
14
+ end
15
+
16
+ # Access underlying post data with symbolized names
17
+ # Possible fields are available for viewing in the (API documentation)[https://github.com/4chan/4chan-API#posts-object]
18
+ # @param key [Symbol] The API field
19
+ # @return [Hash, Array, String, Fixnum]
20
+ def [](key)
21
+ @data[key]
22
+ end
23
+
24
+ # Whether this is the first post in a thread. All op's has a resto of 0
25
+ # @return [true, false]
26
+ def op?
27
+ @data[:resto].zero?
28
+ end
29
+
30
+ # Whether this post has an image associated with it
31
+ # @return [true, false]
32
+ def image?
33
+ !@data[:filename].is_nil?
34
+ end
35
+
36
+ # Url to the image of this post, if any.
37
+ # @return [Image, nil] An Image or nil if no image is present.
38
+ def image_url
39
+ return nil unless image?
40
+
41
+ Image.new(@data)
42
+ end
43
+
44
+ # Url to this post
45
+ # @return [String] The url to this post.
46
+ def url
47
+ direct_link = if @data[:resto].zero?
48
+ @data[:no]
49
+ else
50
+ "#{@data[:resto]}p##{@data[:no]}"
51
+ end
52
+
53
+ "http://boards.4chan.org/#{@board}/thread/#{direct_link}"
54
+ end
55
+
56
+ # The OP to the thread this post is in.
57
+ # @return [Post] A post object for the OP, the instance it was called on if it is the OP.
58
+ def op
59
+ if @data[:resto].zero
60
+ self
61
+ else
62
+ thread.posts[0]
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Trefoil
4
+ # Represents an array of Post objects with additional convenience methods
5
+ class Thread
6
+ def initialize(client, board, id)
7
+ @client = client
8
+ @board = board
9
+ @id = id
10
+ @posts = nil
11
+ end
12
+
13
+ # Get a post based on its position
14
+ # @param index [Integer] the index of the desired post
15
+ # @return [Post, nil] A post object or nil if out of bounds.
16
+ def [](index)
17
+ posts[index]
18
+ end
19
+
20
+ # An array of all posts in the thread
21
+ # @return [Array<Post>] All posts in this thread since last update
22
+ def posts
23
+ @posts = fetch_posts if @posts.nil?
24
+ @posts
25
+ end
26
+
27
+ # Convenience method to get the first post in a thread
28
+ # @return [Post]
29
+ def op
30
+ posts[0]
31
+ end
32
+
33
+ # Refresh post list
34
+ def update
35
+ fetch_posts
36
+ end
37
+
38
+ private
39
+
40
+ # Fetch all posts into
41
+ def fetch_posts
42
+ @client.get("/#{@board}/thread/#{@id}.json")[:posts].each do |post|
43
+ @posts << Post.new(@client, @board, self, post)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Trefoil container module
4
+ module Trefoil
5
+ # Trefoil version number
6
+ VERSION = '0.1.0'
7
+ end
data/lib/trefoil.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'trefoil/board'
4
+ require 'trefoil/client'
5
+ require 'trefoil/image'
6
+ require 'trefoil/post'
7
+ require 'trefoil/thread'
data/trefoil.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift lib
5
+
6
+ require 'trefoil/version'
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = 'trefoil'
10
+ s.version = Trefoil::VERSION
11
+ s.authors = ['swarley']
12
+ s.email = ['matthew.b.carey@gmail.com']
13
+
14
+ s.summary = '4chan Public API Client'
15
+ s.description = 'A client for accessing the 4chan public api.'
16
+ s.homepage = 'https://github.com/swarley/trefoil-rb'
17
+ s.license = 'MIT'
18
+
19
+ s.files = `git ls-files -z`.split(?\x0).reject do |f|
20
+ f =~ /^(spec|doc|examples)/
21
+ end
22
+ s.require_paths = ['lib']
23
+
24
+ s.add_development_dependency 'rake', '~> 12.0'
25
+ s.add_development_dependency 'rspec', '~> 3.8.0'
26
+ s.add_development_dependency 'rubocop', '~> 0.65'
27
+ s.add_development_dependency 'webmock', '~> 3.4.0'
28
+ s.add_development_dependency 'yard', '~> 0.9.9'
29
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trefoil
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - swarley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-03-09 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: '12.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '12.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.8.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.8.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.65'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.65'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.4.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.4.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.9.9
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.9.9
83
+ description: A client for accessing the 4chan public api.
84
+ email:
85
+ - matthew.b.carey@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".codeclimate.yml"
91
+ - ".gitattributes"
92
+ - ".gitignore"
93
+ - ".rspec"
94
+ - ".rubocop.yml"
95
+ - ".travis.yml"
96
+ - Gemfile
97
+ - Gemfile.lock
98
+ - LICENSE
99
+ - Rakefile
100
+ - lib/trefoil.rb
101
+ - lib/trefoil/board.rb
102
+ - lib/trefoil/client.rb
103
+ - lib/trefoil/image.rb
104
+ - lib/trefoil/object.rb
105
+ - lib/trefoil/post.rb
106
+ - lib/trefoil/thread.rb
107
+ - lib/trefoil/version.rb
108
+ - trefoil.gemspec
109
+ homepage: https://github.com/swarley/trefoil-rb
110
+ licenses:
111
+ - MIT
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubygems_version: 3.0.1
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: 4chan Public API Client
132
+ test_files: []