Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Starting to piece the gem together, extracting existing models and sp…

…ecs from the developer.wordnik.com rails app.
  • Loading branch information...
commit 5ec8f46dcadfb20b285169a4d082fafe0c7104eb 1 parent b2556fb
@zeke zeke authored
View
3  .gitignore
@@ -0,0 +1,3 @@
+pkg/*
+*.gem
+.bundle
View
4 Gemfile
@@ -0,0 +1,4 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in wordnik.gemspec
+gemspec
View
57 Gemfile.lock
@@ -0,0 +1,57 @@
+PATH
+ remote: .
+ specs:
+ wordnik (0.0.1)
+ activemodel (= 3.0.3)
+ addressable (= 2.2.4)
+ htmlentities (= 4.2.4)
+ json (= 1.4.6)
+ nokogiri (= 1.4.4)
+ typhoeus (= 0.2.1)
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ activemodel (3.0.3)
+ activesupport (= 3.0.3)
+ builder (~> 2.1.2)
+ i18n (~> 0.4)
+ activesupport (3.0.3)
+ addressable (2.2.4)
+ builder (2.1.2)
+ crack (0.1.8)
+ diff-lcs (1.1.2)
+ htmlentities (4.2.4)
+ i18n (0.5.0)
+ json (1.4.6)
+ mime-types (1.16)
+ nokogiri (1.4.4)
+ rspec (2.4.0)
+ rspec-core (~> 2.4.0)
+ rspec-expectations (~> 2.4.0)
+ rspec-mocks (~> 2.4.0)
+ rspec-core (2.4.0)
+ rspec-expectations (2.4.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.4.0)
+ typhoeus (0.2.1)
+ mime-types
+ vcr (1.5.1)
+ webmock (1.6.2)
+ addressable (>= 2.2.2)
+ crack (>= 0.1.7)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ activemodel (= 3.0.3)
+ addressable (= 2.2.4)
+ htmlentities (= 4.2.4)
+ json (= 1.4.6)
+ nokogiri (= 1.4.4)
+ rspec (= 2.4.0)
+ typhoeus (= 0.2.1)
+ vcr (= 1.5.1)
+ webmock (= 1.6.2)
+ wordnik!
View
9 Rakefile
@@ -0,0 +1,9 @@
+require 'bundler'
+Bundler::GemHelper.install_tasks
+
+require 'rspec/core/rake_task'
+
+RSpec::Core::RakeTask.new('spec')
+
+# If you want to make this the default task
+task :default => :spec
View
23 lib/wordnik.rb
@@ -0,0 +1,23 @@
+require 'wordnik/endpoint'
+require 'wordnik/operation'
+require 'wordnik/operation_parameter'
+require 'wordnik/request'
+require 'wordnik/resource'
+require 'wordnik/response'
+
+class Wordnik
+
+ # See http://tinyurl.com/5t3rhy6 for info on setting up this configuration magic
+ def self.configure
+ yield configuration
+ end
+
+ def self.configuration
+ @configuration ||= Configuration.new
+ end
+
+ class Configuration
+ attr_accessor :api_key
+ end
+
+end
View
31 lib/wordnik/endpoint.rb
@@ -0,0 +1,31 @@
+# To jog the memory: Resource > Endpoint > Operation > OperationParameter
+require 'active_model'
+class Endpoint
+
+ include ActiveModel::Validations
+ include ActiveModel::Conversion
+ extend ActiveModel::Naming
+
+ attr_accessor :path, :description, :operations
+
+ validates_presence_of :path, :description, :operations
+
+ def initialize(attributes = {})
+ attributes.each do |name, value|
+ send("#{name.to_s.underscore.to_sym}=", value)
+ end
+
+ # Generate Operations instances from JSON
+ if self.operations
+ self.operations = self.operations.map do |operationData|
+ Operation.new(operationData)
+ end
+ end
+ end
+
+ # It's an ActiveModel thing..
+ def persisted?
+ false
+ end
+
+end
View
42 lib/wordnik/operation.rb
@@ -0,0 +1,42 @@
+# To jog the memory: Resource > Endpoint > Operation > OperationParameter
+
+class Operation
+ include ActiveModel::Validations
+ include ActiveModel::Conversion
+ extend ActiveModel::Naming
+
+ attr_accessor :http_method, :summary, :notes, :parameters, :response, :open
+
+ validates_presence_of :http_method, :summary, :notes, :parameters, :response, :open
+
+ def initialize(attributes = {})
+ attributes.each do |name, value|
+ send("#{name.to_s.underscore.to_sym}=", value)
+ end
+
+ self.http_method = self.http_method.to_s.downcase
+
+ # Generate OperationParameter instances from JSON
+ if self.parameters
+ self.parameters = self.parameters.map do |parameterData|
+ OperationParameter.new(parameterData)
+ end
+ end
+
+ end
+
+ def get?
+ self.http_method.downcase == "get"
+ end
+
+ # Can this operation be run in the sandbox?
+ def sandboxable?
+ self.get?
+ end
+
+ # It's an ActiveModel thing..
+ def persisted?
+ false
+ end
+
+end
View
36 lib/wordnik/operation_parameter.rb
@@ -0,0 +1,36 @@
+# To jog the memory: Resource > Endpoint > Operation > OperationParameter
+
+class OperationParameter
+ include ActiveModel::Validations
+ include ActiveModel::Conversion
+ extend ActiveModel::Naming
+
+ attr_accessor :name, :description, :required, :param_type, :default_value, :allowable_values
+
+ validates_presence_of :name, :description, :required, :param_type, :default_value, :allowable_values
+
+ def initialize(attributes = {})
+ attributes.each do |name, value|
+ send("#{name.to_s.underscore.to_sym}=", value)
+ end
+ end
+
+ def human_name
+ return "request body" if self.param_type == 'body'
+ self.name
+ end
+
+ def has_allowable_array?
+ self.allowable_values.present? && self.allowable_values.include?(",")
+ end
+
+ def required?
+ self.required
+ end
+
+ # It's an ActiveModel thing..
+ def persisted?
+ false
+ end
+
+end
View
158 lib/wordnik/request.rb
@@ -0,0 +1,158 @@
+class Request
+ require 'uri'
+ require 'addressable/uri'
+ include ActiveModel::Validations
+ include ActiveModel::Conversion
+ extend ActiveModel::Naming
+
+ attr_accessor :host, :port, :path, :format, :params, :body, :http_method, :headers
+
+ validates_presence_of :host, :path, :format, :http_method
+
+ def initialize(http_method, path, attributes={})
+ attributes[:format] ||= "json"
+ attributes[:host] ||= configatron.api.base_uri
+ attributes[:params] ||= {}
+
+ # Set default headers, but allow them to be overridden
+ default_headers = {
+ 'Content-Type' => "application/#{attributes[:format].downcase}",
+ }
+ attributes[:headers] = default_headers.merge(attributes[:headers] || {})
+
+ self.http_method = http_method.to_sym
+ self.path = path
+ attributes.each do |name, value|
+ send("#{name.to_s.underscore.to_sym}=", value)
+ end
+ end
+
+ # Construct a base URL
+ def url
+ u = Addressable::URI.new
+ u.host = self.host.sub(/\/$/, '')
+ u.port = self.port if self.port.present?
+ u.path = self.interpreted_path
+ u.scheme = "http" # For some reason this must be set _after_ host, otherwise Addressable gets upset
+ u.to_s
+ end
+
+ # Iterate over the params hash, injecting any path values into the path string
+ # e.g. /word.{format}/{word}/entries => /word.json/cat/entries
+ def interpreted_path
+ p = self.path
+ self.params.each_pair do |key, value|
+ p = p.gsub("{#{key}}", value.to_s)
+ end
+
+ # Stick a .{format} placeholder into the path if there isn't
+ # one already or an actual format like json or xml
+ # e.g. /words/blah => /words.{format}/blah
+ unless ['.json', '.xml', '{format}'].any? {|s| p.downcase.include? s }
+ p = p.sub(/^(\/?\w+)/, "\\1.#{format}")
+ end
+
+ p = p.sub("{format}", self.format)
+ URI.encode(p)
+ end
+
+ def interpreted_body
+ return unless self.body.present?
+ return self.body.to_json if self.body.is_a?(Hash)
+ self.body
+ end
+
+ # Iterate over all params,
+ # .. removing the ones that are part of the path itself.
+ # .. stringifying values so Addressable doesn't blow up.
+ # .. obfuscating the API key if needed.
+ def query_string_params(obfuscated=false)
+ qsp = {}
+ self.params.each_pair do |key, value|
+ next if self.path.include? "{#{key}}"
+ next if value.blank?
+ value = "YOUR_API_KEY" if key.to_sym == :api_key && obfuscated
+ qsp[key] = value.to_s
+ end
+ qsp
+ end
+
+ # Construct a query string from the query-string-type params
+ def query_string(options={})
+
+ # We don't want to end up with '?' as our query string
+ # if there aren't really any params
+ return "" if query_string_params.blank?
+
+ default_options = {:obfuscated => false}
+ options = default_options.merge(options)
+
+ qs = Addressable::URI.new
+ qs.query_values = self.query_string_params(options[:obfuscated])
+ qs.to_s
+ end
+
+ # Returns full request URL with query string included
+ def url_with_query_string(options={})
+ default_options = {:obfuscated => false}
+ options = default_options.merge(options)
+
+ [url, query_string(options)].join('')
+ end
+
+ def make
+ response = case self.http_method.to_sym
+ when :get
+ Typhoeus::Request.get(
+ self.url_with_query_string,
+ :headers => self.headers.stringify_keys
+ )
+
+ when :post
+ Typhoeus::Request.post(
+ self.url_with_query_string,
+ :body => self.interpreted_body,
+ :headers => self.headers.stringify_keys
+ )
+
+ when :put
+ Typhoeus::Request.put(
+ self.url_with_query_string,
+ :body => self.interpreted_body,
+ :headers => self.headers.stringify_keys
+ )
+
+ when :delete
+ Typhoeus::Request.delete(
+ self.url_with_query_string,
+ :body => self.interpreted_body,
+ :headers => self.headers.stringify_keys
+ )
+ end
+
+ @response_obj = Response.new(response)
+ end
+
+ # If the request has been made, return the existing response
+ # If not, make the request and return the response
+ def response
+ @response_obj || self.make
+ end
+
+ def response_code_pretty
+ return unless @response.present?
+ @response.code.to_s
+ end
+
+ def response_headers_pretty
+ return unless @response.present?
+ # JSON.pretty_generate(@response.headers).gsub(/\n/, '<br/>').html_safe # <- This was for RestClient
+ @response.headers.gsub(/\n/, '<br/>').html_safe # <- This is for Typhoeus
+ end
+
+ # It's an ActiveModel thing..
+ def persisted?
+ false
+ end
+
+end
View
50 lib/wordnik/resource.rb
@@ -0,0 +1,50 @@
+# To jog the memory: Resource > Endpoint > Operation > OperationParameter
+
+class Resource
+
+ include ActiveModel::Validations
+ include ActiveModel::Conversion
+ extend ActiveModel::Naming
+
+ attr_accessor :name, :raw_data, :endpoints, :models
+
+ validates_presence_of :name, :raw_data, :endpoints, :models
+
+ def initialize(attributes = {})
+ attributes.each do |name, value|
+ send("#{name.to_s.underscore.to_sym}=", value)
+ end
+
+ # Generate Endpoint instances from JSON
+ if self.raw_data['endPoints']
+ self.endpoints = self.raw_data['endPoints'].map do |endpointData|
+ Endpoint.new(endpointData)
+ end
+ end
+ end
+
+ def operation_nickname_pairs
+ return unless self.endpoints.present?
+ pairs = {}
+ self.endpoints.map do |endpoint|
+ endpoint.operations.map do |operation|
+ nickname_parts = []
+ nickname_parts << operation.http_method
+ nickname_parts << endpoint.path.gsub(/\{\w+\}/, "").gsub("/", "_").nix(' ').nix('.').underscore
+ nickname = nickname_parts.
+ join("_").
+ gsub(/_+/, "_").
+ gsub("_#{self.name.underscore}", "").
+ gsub(/_$/, "")
+ pairs[nickname] = "#{operation.http_method.upcase} #{endpoint.path}"
+ end
+ end
+ pairs
+ end
+
+ # It's an ActiveModel thing..
+ def persisted?
+ false
+ end
+
+end
View
69 lib/wordnik/response.rb
@@ -0,0 +1,69 @@
+class Response
+ include ActiveModel::Validations
+ include ActiveModel::Conversion
+ extend ActiveModel::Naming
+
+ attr_accessor :raw
+
+ validates_presence_of :raw
+
+ def initialize(raw)
+ self.raw = raw
+ end
+
+ def code
+ raw.code
+ end
+
+ # If body is JSON, parse it
+ # TODO: If body is XML, parse it
+ # Otherwise return raw string
+ def body
+ JSON.parse(raw.body)
+ rescue
+ raw.body
+ end
+
+ def headers
+ h = {}
+ raw.headers_hash.each {|k,v| h[k] = v }
+ h
+ end
+
+ # Extract the response format from the header hash
+ # e.g. {'Content-Type' => 'application/json'}
+ def format
+ headers['Content-Type'].split("/").last.to_sym
+ end
+
+ def json?
+ format == :json
+ end
+
+ def xml?
+ format == :xml
+ end
+
+ def pretty_body
+ return unless body.present?
+ case format
+ when :json
+ JSON.pretty_generate(body).gsub(/\n/, '<br/>').html_safe
+ when :xml
+ xsl = Nokogiri::XSLT(File.open(Rails.root.join("config", "pretty_print.xsl")))
+ xml = Nokogiri(body)
+ coder = HTMLEntities.new
+ coder.encode(xsl.apply_to(xml).to_s)
+ end
+ end
+
+ def pretty_headers
+ JSON.pretty_generate(headers).gsub(/\n/, '<br/>').html_safe
+ end
+
+ # It's an ActiveModel thing..
+ def persisted?
+ false
+ end
+
+end
View
3  lib/wordnik/version.rb
@@ -0,0 +1,3 @@
+module Wordnik
+ VERSION = "0.0.1"
+end
View
26 spec/endpoint_spec.rb
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+describe Endpoint do
+
+ before(:each) do
+ VCR.use_cassette('words', :record => :new_episodes) do
+ @response = Typhoeus::Request.get("http://api.wordnik.com/v4/word.json")
+ end
+
+ @endpoint = Endpoint.new(JSON.parse(@response.body)['endPoints'].first)
+ end
+
+ describe "initialization" do
+
+ it "successfully initializes" do
+ @endpoint.path.should == "/word.{format}/{word}"
+ end
+
+ it "sets operations" do
+ @endpoint.operations.class.should == Array
+ @endpoint.operations.first.class.should == Operation
+ end
+
+ end
+
+end
View
26 spec/operation_parameter_spec.rb
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+describe OperationParameter do
+
+ before(:each) do
+ VCR.use_cassette('words', :record => :new_episodes) do
+ @response = Typhoeus::Request.get("http://api.wordnik.com/v4/word.json")
+ end
+
+ @operation_parameter = OperationParameter.new(JSON.parse(@response.body)['endPoints'].first['operations'].first['parameters'].first)
+ end
+
+ describe "initialization" do
+
+ it "successfully initializes" do
+ @operation_parameter.respond_to?(:name).should == true
+ @operation_parameter.respond_to?(:description).should == true
+ @operation_parameter.respond_to?(:required).should == true
+ @operation_parameter.respond_to?(:param_type).should == true
+ @operation_parameter.respond_to?(:default_value).should == true
+ @operation_parameter.respond_to?(:allowable_values).should == true
+ end
+
+ end
+
+end
View
37 spec/operation_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+describe Operation do
+
+ before(:each) do
+ VCR.use_cassette('words', :record => :new_episodes) do
+ @response = Typhoeus::Request.get("http://api.wordnik.com/v4/word.json")
+ end
+
+ @operation = Operation.new(JSON.parse(@response.body)['endPoints'].first['operations'].first)
+ end
+
+ describe "initialization" do
+
+ it "successfully initializes" do
+ @operation.summary.should =~ /returns the WordObject/i
+ end
+
+ it "sets parameters" do
+ @operation.parameters.class.should == Array
+ @operation.parameters.first.class.should == OperationParameter
+ end
+
+ end
+
+ describe "instance methods" do
+ it "knows if its HTTP method is GET" do
+ @operation.http_method = "GET"
+ @operation.get?.should == true
+ @operation.http_method = "POST"
+ @operation.get?.should == false
+ @operation.http_method = "get"
+ @operation.get?.should == true
+ end
+ end
+
+end
View
155 spec/request_spec.rb
@@ -0,0 +1,155 @@
+require 'spec_helper'
+
+describe Request do
+
+ before(:each) do
+ @default_http_method = :get
+ @default_path = "words/fancy"
+ @default_params = {
+ :params => {:foo => "1", :bar => "2"}
+ }
+ @request = Request.new(@default_http_method, @default_path, @default_params)
+ end
+
+ describe "initialization" do
+ it "sets default response format to json" do
+ @request.format.should == "json"
+ end
+
+ it "sets default host to match configatron's" do
+ @request.host.should == configatron.api.base_uri
+ end
+
+ end
+
+ describe "attr_accessors" do
+
+ it "has working attributes" do
+ @request.host.should == configatron.api.base_uri
+ @request.path.should == "words/fancy"
+ end
+
+ it "allows attributes to be overwritten" do
+ @request.http_method.should == :get
+ @request.http_method = "post"
+ @request.http_method.should == 'post'
+ end
+
+ end
+
+ describe "url" do
+
+ it "constructs a base URL" do
+ @request.url.should == "http://beta.wordnik.com/v4/words.json/fancy"
+ end
+
+ it "constructs a query string" do
+ @request.query_string.should == "?bar=2&foo=1"
+ end
+
+ it "constructs a full url" do
+ @request.url_with_query_string.should == "http://beta.wordnik.com/v4/words.json/fancy?bar=2&foo=1"
+ end
+
+ it "accounts for excessive slashes" do
+ @request = Request.new(:get, "andBurn", @default_params.merge({
+ :host => "slash.com/"
+ }))
+ @request.url.should == "http://slash.com/andBurn.json"
+ end
+
+ end
+
+ describe "path" do
+
+ it "accounts for a total absence of format in the path string" do
+ @request = Request.new(:get, "/word/{word}/entries", @default_params.merge({
+ :format => "xml",
+ :params => {
+ :word => "cat"
+ }
+ }))
+ @request.url.should == "http://beta.wordnik.com/v4/word.xml/cat/entries"
+ end
+
+ it "does string substitution on path params" do
+ @request = Request.new(:get, "/word.{format}/{word}/entries", @default_params.merge({
+ :format => "xml",
+ :params => {
+ :word => "cat"
+ }
+ }))
+ @request.url.should == "http://beta.wordnik.com/v4/word.xml/cat/entries"
+ end
+
+ it "leaves path-bound params out of the query string" do
+ @request = Request.new(:get, "/word.{format}/{word}/entries", @default_params.merge({
+ :params => {
+ :word => "cat",
+ :limit => 20
+ }
+ }))
+ @request.query_string.should == "?limit=20"
+ end
+
+ it "returns a question-mark free (blank) query string if no query params are present" do
+ @request = Request.new(:get, "/word.{format}/{word}/entries", @default_params.merge({
+ :params => {
+ :word => "cat",
+ }
+ }))
+ @request.query_string.should == ""
+ end
+
+ it "removes blank params" do
+ @request = Request.new(:get, "words/fancy", @default_params.merge({
+ :params => {
+ :word => "dog",
+ :limit => "",
+ :foo => "criminy"
+ }
+ }))
+ @request.query_string.should == "?foo=criminy&word=dog"
+ end
+
+ it "obfuscates the API key when needed" do
+ @request = Request.new(:get, "words/fancy", @default_params.merge({
+ :params => {
+ :word => "dog",
+ :api_key => "123456"
+ }
+ }))
+ @request.query_string_params.should == {:word => "dog", :api_key => "123456"}
+ @request.query_string_params(true).should == {:word => "dog", :api_key => "YOUR_API_KEY"}
+
+ @request.query_string.should == "?api_key=123456&word=dog"
+ @request.query_string(:obfuscated => true).should == "?api_key=YOUR_API_KEY&word=dog"
+
+ @request.url_with_query_string.should =~ /123456/
+ @request.url_with_query_string(:obfuscated => true).should =~ /YOUR\_API\_KEY/
+ end
+
+ it "URI encodes the path" do
+ @request = Request.new(:get, "word.{format}/{word}/definitions", @default_params.merge({
+ :params => {
+ :word => "bill gates"
+ }
+ }))
+ @request.url.should =~ /word.json\/bill\%20gates\/definitions/
+ end
+
+ it "converts numeric params to strings" do
+ @request = Request.new(@default_http_method, @default_path, @default_params.merge({
+ :params => {
+ :limit => 100
+ }
+ }))
+
+ @request.interpreted_path.should_not be_nil
+ @request.query_string.should =~ /\?limit=100/
+ @request.url_with_query_string.should =~ /\?limit=100/
+ end
+
+ end
+
+end
View
31 spec/resource_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe Resource do
+
+ before(:each) do
+ VCR.use_cassette('words', :record => :new_episodes) do
+ @response = Typhoeus::Request.get("http://api.wordnik.com/v4/word.json")
+ end
+
+ @default_params = {
+ :name => "word",
+ :raw_data => JSON.parse(@response.body)
+ }
+
+ @resource = Resource.new(@default_params)
+ end
+
+ describe "initialization" do
+
+ it "successfully initializes" do
+ @resource.name.should == "word"
+ end
+
+ it "sets endpoints" do
+ @resource.endpoints.size.should == 10
+ @resource.endpoints.first.class.to_s.should == "Endpoint"
+ end
+
+ end
+
+end
View
49 spec/response_spec.rb
@@ -0,0 +1,49 @@
+require 'spec_helper'
+
+describe Response do
+
+ before(:each) do
+
+ VCR.use_cassette('default_response_request', :record => :new_episodes) do
+ @raw = Typhoeus::Request.get("http://api.wordnik.com/v4/word.json")
+ end
+
+ @response = Response.new(@raw)
+ end
+
+ describe "initialization" do
+ it "sets body" do
+ @response.body.class.should == Hash
+ @response.body.has_key?('endPoints').should == true
+ end
+
+ it "sets code" do
+ @response.code.should == 200
+ end
+
+ it "converts header string into a hash" do
+ @response.headers.class.should == Hash
+ @response.headers['Wordnik-Api-Version'].to_s.should =~ /4\.0/
+ end
+
+ end
+
+ describe "format" do
+
+ it "recognizes json" do
+ @response.format.should == :json
+ @response.json?.should == true
+ end
+
+ it "recognizes xml" do
+ VCR.use_cassette('xml_response_request', :record => :new_episodes) do
+ @raw = Typhoeus::Request.get("http://api.wordnik.com/v4/word.xml/help")
+ end
+ @response = Response.new(@raw)
+ @response.format.should == :xml
+ @response.xml?.should == true
+ end
+
+ end
+
+end
View
4 spec/spec.opts
@@ -0,0 +1,4 @@
+--colour
+--format progress
+--loadby mtime
+--reverse
View
19 spec/spec_helper.rb
@@ -0,0 +1,19 @@
+require 'rubygems'
+require 'bundler/setup'
+require 'wordnik'
+require 'vcr'
+require 'typhoeus'
+require 'json'
+
+RSpec.configure do |config|
+ # some (optional) config here
+end
+
+VCR.config do |config|
+ config.cassette_library_dir = 'spec/vcr'
+ config.stub_with :webmock # or :fakeweb
+end
+
+Wordnik.configure do |config|
+ config.api_key = "12345"
+end
View
11 spec/wordnik_spec.rb
@@ -0,0 +1,11 @@
+require 'spec_helper'
+
+describe Wordnik do
+
+ context "some context" do
+
+ it "should do some cool stuff"
+
+ end
+
+end
View
32 wordnik.gemspec
@@ -0,0 +1,32 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "wordnik/version"
+
+Gem::Specification.new do |s|
+ s.name = "wordnik"
+ s.version = Wordnik::VERSION
+ s.platform = Gem::Platform::RUBY
+ s.authors = ["Zeke Sikelianos", "John McGrath"]
+ s.email = ["zeke@wordnik.com", "john@wordnik.com"]
+ s.homepage = "http://developer.wordnik.com"
+ s.summary = %q{A ruby wrapper for the Wordnik API}
+ s.description = %q{This gem provides a simple interface to the entire Wordnik API. Its methods are defined by the documentation that comes from the API itself, so it is guaranteed to be up to date.}
+
+ s.rubyforge_project = "wordnik"
+
+ s.add_dependency 'typhoeus', '0.2.1'
+ s.add_dependency 'htmlentities', '4.2.4'
+ s.add_dependency 'addressable', '2.2.4'
+ s.add_dependency 'nokogiri', '1.4.4'
+ s.add_dependency 'activemodel', '3.0.3'
+ s.add_dependency 'json', '1.4.6'
+
+ s.add_development_dependency 'rspec', '2.4.0'
+ s.add_development_dependency 'vcr', '1.5.1'
+ s.add_development_dependency 'webmock', '1.6.2'
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+end
Please sign in to comment.
Something went wrong with that request. Please try again.