MWDictionaryAPI provides some simple wrapper for one to start using Merriam Webster Developer API. The difficult thing about the API is its response, which is in XML formatted for presentation rather than programatic access.
The bulk of this gem consists of a parser to help parse the results and reconcile some inconsistencies. I am not aiming to be complete in terms of translating response to ruby objects, but rather pulling in most of the useful and relevant data associated with normal usage of dictionary.
If there are things that you need that are not covered, hopefully you will find the parser class to be easy to extend as that's how this gem was written (see the "Extending the parser" section below). Then let me know and I will be happy to put them in.
Finally, at this point, only the "sd4" product (a designation for 9-11th grade students) has been tested. Nevertheless it's probably safe to use this with the "collegiate", "sd2", "sd3", and "learners" products as well, as the definition for the XML nodes are very similar.
gem install mw_dictionary_api
Go to their website and obtain the API_KEY and product type. For now only sd4
is tested.
collegiate
should work as well. To determine the type of product, notice the API Request URL
on their developer site. The product type is the lower case value of the segment in the URL as
follows:
http://www.dictionaryapi.com/api/v1/references/{sd4}/xml/hypocrite?key=...
require 'mw_dictionary_api'
client = MWDictionaryAPI::Client.new(ENV['MW_SD4_API_KEY'])
result = client.search("one")
To read the content you can do the following
puts result.entries # => an array of hashes, each present an entry
# when your search is slightly off, you will get a list of suggestions
# result.entries.count should be 0
puts result.suggestions
# for convenience
puts result.to_hash
puts result.to_json
To use other types of dictionaries
client = MWDictionaryAPI::Client.new(ENV['MW_COLLEGIATE_API_KEY'], api_type: "collegiate")
# or change it after client has been created
client.api_type = "sd4"
client.api_key = ENV['MW_SD4_API_KEY']
To avoid going over your request limit and provide faster response, responses are cached in memory
client.search('one') # first time hits the api
client.search('one') # fetched directly from memory
# to force the update of the cache
client.search('one', update_cache: true)
# you can also skip the cache for all requests
MWDictionaryAPI::Client.cache = nil
client.search('one') # fetches from web again
Implementing your own cache is easy as well. All you need to do is provide a class that implements
#find(term)
, #add(term, response)
, #remove(term)
, and optionally #clear
methods. You can
easily adapt activerecord
to semi-persist somewhere.
The following is actually the memory implementation used by default:
class SimpleCache
def self.find(term)
cache[term]
end
def self.add(term, result)
cache[term] = result
end
def self.remove(term)
cache.delete(term)
end
# following methods are optional
def self.clear
cache.clear
end
def self.cache
@cache ||= {}
end
end
MWDictionaryAPI::Client.cache = SimpleCache
At its core this gem uses a few different parser objects to parse the result. The response from
Merriam Webster is a list of <entry>
elements. Therefore the default top level parser is
implemented as follows
module MWDictionaryAPI
module Parsers
class ResultParser
include MWDictionaryAPI::Parsable
rule :entries do |data, opts| # entries is the key
data.css("entry").inject([]) do |entries, xml_entry|
parser = Parsers::EntryParser.new(api_type: opts[:api_type], response_format: opts[:response_format])
entries << parser.parse(xml_entry)
entries
end
end
...
end
end
end
The Parsable
module allows you to use the rule
macro. For now, please refer to the source code on how to use (or actually the spec/features/general_spec.rb is probably the best place
to start).
You can extend the parser functionalities by
-
reopening the
MWDictionaryAPI::Parsers::ResultParser
-
or create your own by extending or create from scratch
class MyParser < MWDictionaryAPI::Parsers::ResultParser
...
end
# or
class MyParser
include MWDictionaryAPI::Parsable
...
end
If you create your own, you can use them in 2 ways:
MWDictionaryAPI::Client.parser_class = MyParser # configure before hand
# or
client.search("one", parser_class: MyParser)
Note that any rule
s defined by the parent class are inherited. Nevertheless any rule
s either
defined by the parent or the same class is overwritten if you use the same key.
That's it. Please get in touch with me via github and let me know if you find any problems. I will be happy to fix it.