class Numerous
Numerous
¶ ↑
Primary class for accessing the numerousapp server.
Constructor¶ ↑
You must supply an API key: nr = Numerous.new('nmrs_3xblahblah') You can optionally override the built-in server name nr = Numerous.new('nmrs_3xblahblah', server:'test.server.com')
Server return values¶ ↑
For most operations the NumerousApp server returns a JSON representation of the current or modified object state. This is converted to a ruby Hash of <string-key, value> pairs and returned from the appropriate methods.
For some operations the server returns only a success/failure code. In those cases there is no useful return value from the method; the method succeeds or else raises an exception (containing the failure code).
For the collection operations the server returns a JSON array of dictionary representations, possibly “chunked” into multiple request/response operations.
The enumerator methods (e.g., “metrics”) implement lazy-fetch and hide the details of the chunking from you. They simply yield each individual item (string-key Hash) to your block.
Exception handling¶ ↑
Almost every API that interacts with the server will potentially raise a {NumerousError} (or subclass thereof). This is not noted specifically in the doc for each method unless it might be considered a “surprise” (e.g., ping always returns true else raises an exception). Rescue as needed.
Constants
- APIInfo
path info for the server-level APIs: create a metric, get user info, etc
- RaiseConflict
just a DRY shorthand for use in metricByLabel
Public Class Methods
find an apikey from various default places @param [String] s
See documentation for details; a file name or a key or a "readable" object.
@param [String] credsAPIKey
Key to use in accessing json dict if one is found.
@return [String] the API key.
# File lib/numerousapp.rb, line 1061 def self.numerousKey(s:nil, credsAPIKey:'NumerousAPIKey') if not s # try to get from environment s = ENV['NUMEROUSAPIKEY'] if not s return nil end end closeThis = nil if s == "@-" # creds coming from stdin s = STDIN # see if they are in a file else begin if s.length() > 0 # is it a string or a file object? # it's stringy - if it looks like a file open it or fail begin if s.length() > 1 and s[0] == '@' s = open(s[1..-1]) closeThis = s elsif s[0] == '/' or s[0] == '.' s = open(s) closeThis = s end rescue return nil end end rescue NoMethodError # it wasn't stringy, presumably it's a "readable" end end # well, see if whatever it is, is readable, and go with that if it is begin v = s.read() if closeThis closeThis.close() end s = v rescue NoMethodError end # at this point s is either a JSON or a naked cred (or bogus) begin j = JSON.parse(s) rescue TypeError, JSON::ParserError j = {} end # # This is kind of a hack and might hide some errors on your part # if not j.include? credsAPIKey # this is how the naked case happens # replace() bcs there might be a trailing newline on naked creds # (usually happens with a file or stdin) j[credsAPIKey] = s.sub("\n",'') end return j[credsAPIKey] end
Public Instance Methods
Create a brand new metric on the server.
@param label [String] Required. Label for the metric. @param value [Fixnum,Float] Optional (keyword arg). Initial value. @param attrs [Hash] Optional (keyword arg). Initial attributes. @return [NumerousMetric]
@example Create a metric with label ‘bozo’ and set value to 17
nr = Numerous.new('nmrs_3vblahblah') m = nr.createMetric('bozo') m.write(17)
@example Same example using the value keyword argument.
m = nr.createMetric('bozo', value:17)
@example Same example but also setting the description attribute
m = nr.createMetric('bozo', value:17, attrs:{"description" => "a clown"})
# File lib/numerousapp.rb, line 935 def createMetric(label, value:nil, attrs:{}) api = makeAPIcontext(APIInfo[:create], :POST) j = attrs.clone j['label'] = label if value j['value'] = value end v = simpleAPI(api, jdict:j) return metric(v['id']) end
Instantiate a metric object to access a metric from the server. @return [NumerousMetric] metric object @param id [String]
Required. Metric ID (something like '2319923751024'). NOTE: If id is bogus this will still "work" but (of course) errors will be raised when you do something with the metric.
@see createMetric
createMetric @see NumerousMetric#validate
validate
# File lib/numerousapp.rb, line 958 def metric(id) return NumerousMetric.new(id, self) end
Version of metric() that accepts a name (label) instead of an ID, and can even process it as a regexp.
@param [String] labelspec The name (label) or regexp @param [String] matchType ‘FIRST’,‘BEST’,‘ONE’,‘STRING’ or ‘ID’
# File lib/numerousapp.rb, line 975 def metricByLabel(labelspec, matchType:'FIRST') bestMatch = [ nil, 0 ] if not matchType matchType = 'FIRST' end if not ['FIRST', 'BEST', 'ONE', 'STRING', 'ID'].include?(matchType) raise ArgumentError end # Having 'ID' as an option simplifies some automated use cases # (e.g., test vectors) because you can just pair ids and matchTypes # and simply always call ByLabel even for native (nonlabel) IDs # We add the semantics that the result is validated as an actual ID if matchType == 'ID' rv = metric(labelspec) if not rv.validate() rv = nil end return rv end # if you specified STRING and sent a regexp... or vice versa if matchType == 'STRING' and labelspec.instance_of?(Regexp) labelspec = labelspec.source elsif matchType != 'STRING' and not labelspec.instance_of?(Regexp) labelspec = /#{labelspec}/ end self.metrics do |m| if matchType == 'STRING' # exact full match required if m['label'] == labelspec if bestMatch[0] RaiseConflict.call(bestMatch[0]['label'], m['label']) end bestMatch = [ m, 1 ] # the length is irrelevant with STRING end else mm = labelspec.match(m['label']) if mm if matchType == 'FIRST' return self.metric(m['id']) elsif (matchType == 'ONE') and (bestMatch[1] > 0) RaiseConflict.call(bestMatch[0]['label'], m['label']) end if mm[0].length > bestMatch[1] bestMatch = [ m, mm[0].length ] end end end end rv = nil if bestMatch[0] rv = self.metric(bestMatch[0]['id']) end end
All metrics for the given user (default is your own)
@param [String] userId
optional - numeric id (represented as a string) of user
@yield [m] metrics @yieldparam m [Hash] String-key representation of one metric @return self
# File lib/numerousapp.rb, line 868 def metrics(userId:nil, &block) chunkedIterator(APIInfo[:metricsCollection], { userId: userId }, block) return self end
Obtain array of the “most popular” metrics.
@note this returns the array; it is not an Enumerator
@param [Fixnum] count
optional - number of metrics to return
@return [Array] Array of hashes (metric string dicts). Each element
represents a particular popular metric.
# File lib/numerousapp.rb, line 898 def mostPopular(count:nil) api = makeAPIcontext(APIInfo[:popular], :GET, {count: count}) return simpleAPI(api) end
Verify connectivity to the server
@return [true] Always returns true connectivity if ok.
Raises an exception otherwise.
@raise [NumerousAuthError] Your credentials are no good. @raise [NumerousError] Other server (or network) errors.
# File lib/numerousapp.rb, line 911 def ping ignored = user() return true # errors raise exceptions end
All subscriptions for the given user (default is your own)
@param [String] userId
optional - numeric id (represented as a string) of user
@yield [s] subscriptions @yieldparam s [Hash] String-key representation of one subscription @return self
# File lib/numerousapp.rb, line 882 def subscriptions(userId:nil, &block) chunkedIterator(APIInfo[:subscriptions], { userId: userId }, block) return self end
Obtain user attributes
@param [String] userId
optional - numeric id (represented as a string) of user
@return [Hash] user representation (string-key hash)
# File lib/numerousapp.rb, line 836 def user(userId:nil) api = makeAPIcontext(APIInfo[:user], :GET, {userId: userId}) return simpleAPI(api) end
Set the user’s photo
@note the server enforces an undocumented maximum data size.
Exceeding the limit will raise a NumerousError (HTTP 413 / Too Large)
@param [String,#read] imageDataOrReadable
Either a binary-data string of the image data or an object with a "read" method. The entire data stream will be read.
@param [String] mimeType
Optional(keyword arg). Mime type.
@return [Hash] updated user representation (string-key hash)
# File lib/numerousapp.rb, line 853 def userPhoto(imageDataOrReadable, mimeType:'image/jpeg') api = makeAPIcontext(APIInfo[:user], :photo) mpart = { :f => imageDataOrReadable, :mimeType => mimeType } return simpleAPI(api, multipart: mpart) end