trefoil 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 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: []