Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ rakelib
.env
Rakefile
.gem_rbs_collection/
/docs/
9 changes: 9 additions & 0 deletions docscribe.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
rbs:
enabled: true
collection: true
collapse_generics: true

filter:
exclude:
- Genius::Errors::DynamicRescue.rescue_from
31 changes: 9 additions & 22 deletions lib/extensions/deep_find.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,11 @@
# frozen_string_literal: true

class Hash # :nodoc:
# +Hash#deep_find+ -> value
# Searches for a key in nested hashes and arrays. Returns matching values or +nil+.
#
# @param [Object] key A key, which value should be found
# @param [FalseClass] uniq A flag to make values unique in an array
# @return [Object] output depends on key value
# This method is an extension for Hash core class to search for a value of a key in N-nested
# hash. It provides search for multiple values if key appears more than once. For e.g.:
#
# @example
# musicians = { "Travis Scott" => { "28" => ["Highest in the Room", "Franchise"] },
# "Adele" => { "19" => ["Day Dreamer", "Best for Last"] },
# "Ed Sheeran" => { "28" => ["Shape of You", "Castle on the Hill"] } }
# musicians.deep_find("19") #=> ["Day Dreamer", "Best for Last"]
# musicians.deep_find("Adele") #=> {"19"=>["Day Dreamer", "Best for Last"]}
# musicians.deep_find("28") #=> [["Highest in the Room", "Franchise"], ["Shape of You", "Castle on the Hill"]]
#
# If values are identical, they will be returned in a single copy. You can disable this
# feature with special param +uniq+, which is +true+ by default. For e.g.:
#
# @example
# h = {"a" => "b", "c" => {"a" => "b"}}
# h.deep_find("a") #=> "b", instead ["b", "b"]
# @todo change uniq true to uniq false
# @param [Object] key Key to search for.
# @param [Boolean] uniq If +true+, deduplicates results.
# @return [nil, Object]
def deep_find(key, uniq: true)
result = collect_values(key)
result.compact!
Expand All @@ -36,6 +18,11 @@ def deep_find(key, uniq: true)

private

# Recursively collects values for a key from nested hashes.
#
# @private
# @param [Object] key Key to search for.
# @return [Array]
def collect_values(key)
result = [self[key]]
each_value do |value|
Expand Down
2 changes: 1 addition & 1 deletion lib/extensions/token_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class Object # :nodoc:
# +Object#token_ext+ -> String
#
# Helper method to check if token is correct
# @param [String] token Token to access https://api.genius.com.
# @param [String?] token Token to access https://api.genius.com.
# @return [String]
def token_ext(token)
token || Genius::Auth.instance_variable_get(:@token)
Expand Down
2 changes: 1 addition & 1 deletion lib/extensions/unescape.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class String # :nodoc:
#
# String#unescape method unescapes input JSON strings.
#
# @return [String (frozen)]
# @return [String]
def unescape
string = gsub(/(?<!\\)(\\")/, '"')
string.gsub(/(?<!\\)(\\\\")/, '\"')
Expand Down
5 changes: 2 additions & 3 deletions lib/genius/api/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ class << self
#
# An alias to {Genius::Account.account me} method
#
# @param [String] token Token to access https://api.genius.com.
# @param [String?] token Token to access https://api.genius.com.
# @raise [TokenError] if +token+ or +Genius::Auth.token+ are invalid.
# @return [Hash]
# @return [NilClass] if TokenError exception raised.
# @return [Hash, nil] if TokenError exception raised.
# This method is a standard Genius API {request}[https://docs.genius.com/#search-h2] to get
# account info. Output +JSON+ is translated to Hash structure to make it easy to work with account fields.
#
Expand Down
182 changes: 26 additions & 156 deletions lib/genius/api/annotations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,145 +5,15 @@ module Genius
# web page (hosted anywhere). The part of a document that an annotation is attached to is called a referent.
module Annotations
class << self
# +Genius::Annotations.annotations+ -> true or false
#
# @param [Object] id Identification of annotations resource.
# @param [Object] action Action to do during PUT request. Possible actions: nil, upvote, downvote, unvote.
# @param [String] token Token to access https://api.genius.com.
# @param [String (frozen)] http_verb HTTP verb for request. Possible verbs: get, post, put, delete.
# @param [Hash] options Options for PUT response.
# @option options [String] :markdown The text for the note, in
# {markdown}[https://help.github.com/articles/github-flavored-markdown/]
# @option options [String] :raw_annotatable_url The original URL of the page.
# @option options [String] :fragment The highlighted fragment.
# @option options [String] :before_html The HTML before the highlighted fragment (prefer up to 200 characters).
# @option options [String] :after_html The HTML after the highlighted fragment (prefer up to 200 characters).
# @option options [String] :canonical_url The href property of the <code><link rel="canonical"></code> tag
# on the page. Including it will help make sure newly created annotation appear on the correct page.
# @option options [String] :og_url The content property of the <code><meta property="og:url"></code> tag on
# the page. Including it will help make sure newly created annotation appear on the correct page.
# @option options [String] :title The title of the page.
# @raise [ArgumentError] if +action+ got incorrect value.
# @raise [TokenError] if +token+ or +Genius::Auth.token+ are invalid.
# @return [NilClass] if TokenError exceptions raised.
#
# +GET /annotations/:id+<br>
# Data for a specific annotation.
#
# @example Example usage
# Genius::Annotations.annotations(id: 10225840)
#
# +POST /annotations+<br>
# Requires scope: _create_annotation_
#
# Creates a new annotation on a public web page. The returned value will be the new annotation object, in the
# same form as would be returned by GET /annotation/:id with the new annotation's ID. Requires JSON payload.
# @example Example Payload
# {
# "annotation": {
# "body": {
# "markdown": "hello **world!**"
# }
# },
# "referent": {
# "raw_annotatable_url": "http://seejohncode.com/2014/01/27/vim-commands-piping/",
# "fragment": "execute commands",
# "context_for_display": {
# "before_html": "You may know that you can ",
# "after_html": " from inside of vim, with a vim command:"
# }
# },
# "web_page": {
# "canonical_url": null,
# "og_url": null,
# "title": "Secret of Mana"
# }
# }
#
# Example usage
# Genius::Annotations.annotation(id:, http_verb: "post", markdown: "Foo **Bar**",
# raw_annotatable_url: "https://example.com")
# will reproduce JSON object via +Genius::Annotations.post_payload+ method. According to last example it will
# return
# {
# annotation: {
# body: {
# markdown: "Foo **Bar**"
# }
# },
# referent: {
# raw_annotatable_url: "https://example.com",
# fragment: null,
# context_for_display: {
# before_html: null,
# after_html: null
# }
# },
# web_page: {
# canonical_url: null,
# og_url: null,
# title: null
# }
# }
#
# There is a full list of possible params:
# * annotation
# * body
# * markdown - The text for the note, in
# [markdown](https://help.github.com/articles/github-flavored-markdown/) _(Required)_
# * referent
# * raw_annotatable_url - The original URL of the page _(Required)_
#
# * fragment - The highlighted fragment _(Required)_
# * context_for_display
#
# * before_html - The HTML before the highlighted fragment (prefer up to 200 characters)
#
# * after_html - The HTML after the highlighted fragment (prefer up to 200 characters)
# * web_page <i>At least one required</i>
#
# * canonical_url - The href property of the +<link rel="canonical">+ tag on the page. Including it will
# help make sure newly created annotation appear on the correct page
#
# * og_url - The content property of the tag on the page. Including it will help make sure newly created
# annotation appear on the correct page
#
# * title - The title of the page
#
# +PUT /annotations/:id+<br>
# Requires scope: _manage_annotation_<br>
# Updates an annotation created by the authenticated user. Accepts the same parameters as POST /annotation above.
#
# @example Example usage
# Genius::Annotations.annotations(id: 10225840, http_verb: "put")
#
# +DELETE /annotations/:id+<br>
# Requires scope: _manage_annotation_<br>
# Deletes an annotation created by the authenticated user.
#
# @example Example usage
# Genius::Annotations.annotations(id: 10225840, http_verb: "delete")
#
# +PUT /annotations/:id/upvote+<br>
# Requires scope: _vote_<br>
# Votes positively for the annotation on behalf of the authenticated user.
#
# @example Example usage
# Genius::Annotations.annotations(id: 10225840, http_verb: "put", action: "upvote")
#
# +PUT /annotations/:id/downvote+<br>
# Requires scope: _vote_<br>
# Votes negatively for the annotation on behalf of the authenticated user.
#
# @example Example usage
# Genius::Annotations.annotations(id: 10225840, http_verb: "put", action: "vote")
#
# +PUT /annotations/:id/unvote+<br>
# Requires scope: _vote_<br>
# Removes the authenticated user's vote (up or down) for the annotation.
#
# @example Example usage
# Genius::Annotations.annotations(id: 10225840, http_verb: "put", action: "vote")
# Data for a specific annotation. Supports GET, POST, PUT, DELETE verbs with optional voting actions.
#
# @param [Integer] id ID of the annotation.
# @param [String?] action Action for PUT request: +nil+, +upvote+, +downvote+, or +unvote+.
# @param [String?] token Token to access https://api.genius.com.
# @param [String] http_verb HTTP verb: +get+, +post+, +put+, +delete+.
# @param [Hash] options Options for POST/PUT payload.
# @raise [ArgumentError] if +action+ is set for non-PUT request.
# @return [Hash, nil]
def annotations(id:, action:, token:, http_verb: 'get', options: {})
return if token.nil? && !Auth.authorized?.nil?

Expand All @@ -155,10 +25,16 @@ def annotations(id:, action:, token:, http_verb: 'get', options: {})

private

# +Genius::Annotations.request+ -> HTTParty::Response
# Sends an HTTP request based on the verb and returns the raw response.
#
# @private
# @see .annotations
# @param [Integer] id ID of the annotation.
# @param [String?] action Action for PUT request.
# @param [String?] token Token to access https://api.genius.com.
# @param [String] http_verb HTTP verb.
# @param [Hash] options Options for POST/PUT payload.
# @raise [ArgumentError] if HTTP verb is invalid.
# @return [HTTParty::Response]
def request(id:, action:, token:, http_verb:, options:)
case http_verb
when 'get' then HTTParty.get("#{Api::RESOURCE}/annotations/#{id}?access_token=#{token_ext(token)}")
Expand All @@ -170,10 +46,15 @@ def request(id:, action:, token:, http_verb:, options:)
end
end

# +Genius::Annotations.put_request+ -> HTTParty::Response
# Sends a PUT request with optional voting action.
#
# @private
# @see .annotations
# @param [Integer] id ID of the annotation.
# @param [String?] action Action: +nil+, +upvote+, +downvote+, or +unvote+.
# @param [String?] token Token to access https://api.genius.com.
# @param [Hash] options Options for PUT payload.
# @raise [ArgumentError] if +action+ is invalid.
# @return [HTTParty::Response]
def put_request(id:, action:, token:, options:)
case action
when nil then HTTParty.put("#{Api::RESOURCE}/annotations/#{id}/#{action}?access_token=#{token_ext(token)}",
Expand All @@ -186,21 +67,10 @@ def put_request(id:, action:, token:, options:)
end
end

# +Genius::Annotations.post_payload+ -> String
# Builds a JSON payload for POST and PUT requests from options.
#
# @private
# @param [Hash] options Options for PUT response.
# @option options [String] :markdown The text for the note, in
# {markdown}[https://help.github.com/articles/github-flavored-markdown/].
# @option options [String] :raw_annotatable_url The original URL of the page.
# @option options [String] :fragment The highlighted fragment.
# @option options [String] :before_html The HTML before the highlighted fragment (prefer up to 200 characters).
# @option options [String] :after_html The HTML after the highlighted fragment (prefer up to 200 characters).
# @option options [String] :canonical_url The href property of the <code><link rel="canonical"></code> tag
# on the page. Including it will help make sure newly created annotation appear on the correct page.
# @option options [String] :og_url The content property of the <code><meta property="og:url"></code> tag on
# the page. Including it will help make sure newly created annotation appear on the correct page.
# @option options [String] :title The title of the page.
# @param [Hash] options Options containing +:markdown+, +:raw_annotatable_url+, +:fragment+, etc.
# @return [String]
def post_payload(options: {})
{
Expand Down
Loading
Loading