lexile 0.0.5 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a9d8c608432170762a600d4381ab5bc7eec7017
4
- data.tar.gz: 55283e4b04b6abd7d4623cf091b870cbaff7b2b4
3
+ metadata.gz: 6fb1bf0a8ef1cde0481ba7c7f71b612705ee2ba1
4
+ data.tar.gz: 14b12295e34c5dbfc326e98fb403c3bdce1e979e
5
5
  SHA512:
6
- metadata.gz: 8680d0ef2d8c642a47a559aecd47b82a72dc246de2fbdb14a62ffe3b65664e419a3766585244b9b478c80ccf1fc04264194459ce1db645014a63f96c7dee4df5
7
- data.tar.gz: b61f7210672836096a621cfbd1c395f0b397719fa2f4b5ade0c8590557b196b9be8e839ce2344434aa288f86c75daf36fea8593b3fdcaa052cc0b6627bc16ebf
6
+ metadata.gz: 14f9461ddfb86c80d6568ed4e044d5315772b7bb58e79782b6617fe4739db8846dec8aadbb886c8890698a78b96959bba6a54eac82ac6a05e0759948766c6d36
7
+ data.tar.gz: 0718ec372bf2e13c02c2e74f624ec258b9bea2de351d4d154a500bf52144cee10fb256bb97b8707e50e68f08b177c988b9882300b610eb5814b07f2ba50609f2
data/Gemfile CHANGED
@@ -3,15 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in lexile.gemspec
4
4
  gemspec
5
5
 
6
- gem 'httparty', '~> 0.10'
7
- gem 'hashie'
8
-
9
- group :development, :test do
10
- gem 'rspec', '~> 2'
11
- gem 'webmock'
12
- gem 'vcr', '~> 2.8'
13
- gem 'jeweler'
14
- gem 'factory_girl'
15
- end
16
-
17
6
  gem "codeclimate-test-reporter", group: :test, require: nil
data/README.md CHANGED
@@ -8,15 +8,18 @@
8
8
  This gem wraps a portion of the Lexile database API. You need to obtain an
9
9
  authorized username and password from Lexile to use the API. This gem is not
10
10
  meant to be a comprenhensive implementation of the API just a bare bones
11
- "Find the Lexile for a Specific Book" solution.
11
+ "Find the Lexile for a Specific Book or Update your Lexile DB" solution.
12
12
 
13
- The gem only covers the endpoints to the `book` resource, the `category` and
13
+ The gem only covers the endpoint to the `book` resource, the `category` and
14
14
  `serial` resources are beyond the scope of this gem . If you need access
15
15
  to these resources feel free to submit a PR with code and specs.
16
16
 
17
- The gem does not support pagination for result-sets longer than 20 books, while
18
- the API contains all provisions for pagination, it is beyond the scope of the
19
- gem to expose those.
17
+ The gem now supports pagination for long result-sets using the `next` and `previous` links
18
+ of the `meta` element of the response. Pagination is implemented as an Enumerable and it is
19
+ transparent when you traverse the enumerable with each, select, map, etc.... ( `count` will
20
+ paginate the whole collection, a more efficient implementation using the `total_count` from
21
+ the `meta` is left as practice for the reader)
22
+
20
23
 
21
24
  ## Installation
22
25
 
@@ -39,7 +42,8 @@ Or install it yourself as:
39
42
  end
40
43
 
41
44
  ## Usage
42
-
45
+ ```
46
+ # FIND BY LEXILE ID
43
47
  >> b = Lexile.books.show("315833")
44
48
  #<Lexile::Book id= "315833" ISBN="006201272X" ISBN13="9780062012722" ... >
45
49
 
@@ -47,24 +51,44 @@ Or install it yourself as:
47
51
  "It Happened to Nancy: By An Anonymous Teenager: A True Story from Her Diary"
48
52
 
49
53
 
50
-
51
- >> b = Lexile.books.find_by_isbn13("9780062012722")
54
+ # FIND BY ISBN13
55
+ >> b = Lexile.books.find_by_isbn13("9780062012722").first
52
56
  [#<Lexile::Book ISBN="006201272X" ISBN13="9780062012722" ... >]
53
57
 
54
58
  >> b[0].title
55
59
  "It Happened to Nancy: By An Anonymous Teenager: A True Story from Her Diary"
56
60
 
57
61
 
58
-
59
- >> b = Lexile.books.find_by_title("to Nancy")
60
- [#<Lexile::Book ISBN="0380773155" ISBN13="9780380773152" ... >, #<Lexile::Book ISBN="006201272X" ISBN13="9780062012722" ... >]
61
-
62
- >> b.length
63
- 2
64
-
65
- >> b[0].title
62
+ # FIND BY TITLE
63
+ >> books = Lexile.books.find_by_title("to Nancy")
64
+ books.count
65
+ >> 2
66
+
67
+ books.each do |b|
68
+ puts b.ISBN13
69
+ end
70
+ >> 9780380773152
71
+ >> 9780062012722
72
+
73
+ >> books.first.title
66
74
  "It Happened to Nancy: By An Anonymous Teenager: A True Story from Her Diary"
67
75
 
76
+ # GET LATEST UPDATES TO DB ( supports paging )
77
+ books = Lexile.books.find( timestamp__gte: '2015-08-04', limit:100 )
78
+ # will load pages of 100 elements at a time until there are no further pages
79
+ books.each do |b|
80
+ ....
81
+ end
82
+
83
+ books.first
84
+ >>[#<Lexile::Book ISBN="006201272X" ISBN13="9780062012722" ... >]
85
+
86
+ books.fist(20).last
87
+ >>[#<Lexile::Book ISBN="00620XXX" ISBN13="9780063013733" ... >]
88
+
89
+ books.count
90
+ >>107 #will paginate through the whole collection
91
+ ```
68
92
 
69
93
  ## Contributing
70
94
 
@@ -78,7 +102,7 @@ Or install it yourself as:
78
102
 
79
103
  The MIT License (MIT)
80
104
 
81
- Copyright (c) 2014 Curriculet Inc
105
+ Copyright (c) 2015 Curriculet Inc
82
106
 
83
107
  Permission is hereby granted, free of charge, to any person obtaining a copy
84
108
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "lexile"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ Lexile.configure do |config|
14
+ config.username = ENV['LEXILE_USERNAME']
15
+ config.password = ENV['LEXILE_PASSWORD']
16
+ end
17
+
18
+
19
+ require "irb"
20
+ IRB.start
@@ -22,4 +22,12 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_runtime_dependency "httparty", "~> 0.10"
24
24
  spec.add_runtime_dependency "hashie"
25
+
26
+ spec.add_development_dependency "bundler", ">= 1.3.0","< 2.0"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rspec", "~> 2"
29
+ spec.add_development_dependency "webmock"
30
+ spec.add_development_dependency "vcr", "~> 2.8"
31
+ spec.add_development_dependency "jeweler"
32
+
25
33
  end
@@ -15,6 +15,9 @@ require 'lexile/book'
15
15
  require 'lexile/api/resource'
16
16
  require 'lexile/api/books'
17
17
  require 'lexile/api/endpoints'
18
+ require 'lexile/api/page'
19
+ require 'lexile/api/page_list'
20
+ require 'lexile/api/result_list'
18
21
 
19
22
  module Lexile
20
23
  extend Configuration
@@ -4,13 +4,14 @@ module Lexile
4
4
  api_model Lexile::Book
5
5
 
6
6
  def show id
7
- response = @client.get( "#{ api_model.api_path }/#{id}" )
8
- api_model.parse(response.body)
7
+ response_json = @client.get( "#{Lexile.api_version}/#{ api_model.api_path }/#{id}" )
8
+ api_model.parse( response_json )
9
9
  end
10
10
 
11
11
  def find( query_params )
12
- response = @client.get( "#{ api_model.api_path }", query_params )
13
- api_model.parse(response.body)
12
+ Lexile::Api::PageList.new( @client, api_model, query_params ).to_results_list
13
+ #response_json = @client.get( "#{ api_model.api_path }", query_params )
14
+ #api_model.parse( response_json )
14
15
  end
15
16
 
16
17
  def find_by_isbn13 isbn13
@@ -52,12 +52,13 @@ module Lexile
52
52
 
53
53
  yield get_args if block_given?
54
54
 
55
- #puts "CALLING API: #{Lexile.api_url}#{path} ===#{get_options}"
55
+ puts "CALLING API: #{Lexile.api_url}#{path} ===#{get_args}"
56
56
  response = self.class.get( path, get_args)
57
57
 
58
58
  case response.code
59
59
  when 200..201
60
60
  response
61
+ JSON.parse( response.body )
61
62
  when 400
62
63
  raise Lexile::BadRequest.new(response, params)
63
64
  when 401
@@ -84,12 +85,12 @@ module Lexile
84
85
  # @return [Hash] The properly formated get_options.
85
86
  def build_get_args( params={}, user_headers={})
86
87
  get_args = {}
87
- query ={ format: 'json'} #all requests get this query params
88
+ query ={} #all requests get these query params
88
89
 
89
90
  query.merge!(params)
90
91
 
91
- # pass any headers
92
- headers ={}
92
+
93
+ headers ={ 'Accept' => 'application/json'} #all requests get these headers
93
94
  headers.merge!( user_headers )
94
95
 
95
96
  get_args[:query] = query
@@ -0,0 +1,74 @@
1
+ module Lexile
2
+ module Api
3
+ # Represents a page of data
4
+ class Page
5
+ include Enumerable
6
+
7
+ # Request a page of data and store the results in this instance
8
+ # @api private
9
+ # @return [Lexile::Api::Page]
10
+ # @example
11
+ # page = Page.new '/v2.1/book'
12
+ def initialize(client, api_model, uri, query_params = {})
13
+ @client = client
14
+ @api_model = api_model
15
+ @uri = uri
16
+ @query_params = query_params
17
+
18
+ response_json = @client.get( uri, @query_params )
19
+ @all = api_model.parse(response_json)
20
+
21
+ raise Lexile::CannotProcessResponse.new('[:meta] is not present in response') unless response_json.has_key?('meta')
22
+
23
+ @limit = response_json['meta']['limit']
24
+ @next = response_json['meta']['next']
25
+ #puts "NEXT URI IS ==>#{@next}<=="
26
+ @offset = response_json['meta']['offset']
27
+ @previous = response_json['meta']['previous']
28
+ @total_count = response_json['meta']['total_count']
29
+ end
30
+
31
+ # Gets next page if one is present, nil otherwise
32
+ # @api private
33
+ # @return [Lexile::Api::Page, nil] Next page, or nil if last
34
+ # @example
35
+ # next_page = page.next
36
+ # unless next_page.nil?
37
+ # next_page.each do |elem| puts elem; end
38
+ def next
39
+ return nil if @next.nil?
40
+ Page.new( @client, @api_model, @next, {} )
41
+ end
42
+
43
+ # Iterate over all elements in the page
44
+ # @api private
45
+ # @return [Array] List of all elements
46
+ # @example
47
+ # page.each { |elem| puts elem }
48
+ def each(&blk)
49
+ @all.each(&blk)
50
+ end
51
+
52
+ # Get all elements in page
53
+ # @api private
54
+ # @return [Array] List of all elements
55
+ # @example
56
+ # all_elems = page.all
57
+ attr_reader :all
58
+
59
+ # Retrieve the last element or n elements in the resource
60
+ # @api public
61
+ # @param num [nil, Integer] If nil, last elem; else, num elems to fetch
62
+ # @return [Lexile::Model, Lexile::Api::Page] elem, or
63
+ # elems found. If list, sorted in ascending order of ids.
64
+ # @example
65
+ # books = Lexile.books.first(20)
66
+ # last_elem = books.last
67
+ # last_elems = books.last 5
68
+ def last(num = nil)
69
+ return @all.last num if num
70
+ @all.last
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,44 @@
1
+ module Lexile
2
+ module Api
3
+ # Handles paginated requests.
4
+ class PageList
5
+ include Enumerable
6
+
7
+ # Create a new PageList, without making any requests immediately
8
+ # @api private
9
+ # @return [PageList]
10
+ def initialize(client, api_model, query_params = {})
11
+ @client = client
12
+ @api_model = api_model
13
+ @uri = "#{Lexile.api_version}/#{api_model.api_path}"
14
+ @query_params = query_params
15
+ end
16
+
17
+ # Iterate through each page, making requests as you iterate
18
+ # @api private
19
+ # @return [nil]
20
+ # @example
21
+ # pagelist.each do |page|
22
+ # page.each do |elem|
23
+ # puts elem
24
+ # end
25
+ # end
26
+ def each
27
+ page = Page.new( @client, @api_model, @uri, @query_params )
28
+ until page.nil?
29
+ yield page
30
+ page = page.next
31
+ end
32
+ end
33
+
34
+ # Convert PageList into a ResultsList for easier iteration
35
+ # @api private
36
+ # @return [Lexile::Api::ResultsList]
37
+ # @example
38
+ # pagelist.to_results_list.each { |elem| puts elem }
39
+ def to_results_list
40
+ Lexile::Api::ResultsList.new( self )
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,31 @@
1
+ module Lexile
2
+ module Api
3
+ # Represents a list of results for a paged request.
4
+ class ResultsList
5
+ include Enumerable
6
+
7
+ # Create a results list from a PageList
8
+ # @api private
9
+ # @return [ResultsList]
10
+ def initialize( page_list )
11
+ @pages = page_list
12
+ end
13
+
14
+ # Iterate over results list
15
+ # @api public
16
+ # @return [nil]
17
+ # @example
18
+ # results = Lexile::Book.find # returns a ResultsList
19
+ # results.each do |book|
20
+ # puts district.title
21
+ # end
22
+ def each
23
+ @pages.each do |page|
24
+ page.each do |elem|
25
+ yield elem
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -2,7 +2,7 @@ module Lexile
2
2
  class Book < Hashie::Mash
3
3
  include Lexile::Model
4
4
 
5
- api_path '/book'
5
+ api_path 'book'
6
6
 
7
7
  # Book Resource
8
8
  #
@@ -6,8 +6,8 @@ module Lexile
6
6
  #@!visibility private
7
7
  VALID_CONFIG_KEYS = VALID_CONNECTION_KEYS + VALID_OPTIONS_KEYS
8
8
 
9
- DEFAULT_ENDPOINT = 'https://fabapi.lexile.com/api/fab'
10
- DEFAULT_API_VERSION = 'v2'
9
+ DEFAULT_ENDPOINT = 'https://fabapi.lexile.com'
10
+ DEFAULT_API_VERSION = '/api/fab/v2.1'
11
11
  DEFAULT_USER_AGENT = 'Lexile API Ruby Gem by Curriculet'.freeze
12
12
  DEFAULT_TIMEOUT = nil
13
13
  DEFAULT_TESTING = false
@@ -45,15 +45,19 @@ module Lexile
45
45
  # Interpolate the base url for all calls
46
46
  # return [String] the base url for all api calls
47
47
  def api_url( path = nil)
48
- [endpoint,api_version,path].compact.join('/')
48
+ [endpoint,path].compact.join('/')
49
+ end
50
+
51
+ def config
52
+ self
49
53
  end
50
54
 
51
55
  # Yields itself for use in the configuration block
52
56
  # @example
53
57
  # Lexile.configure do |c|
54
58
  # c.api_key = <MY-API-KEY>
55
- # c.api_verion = 'v2'
56
- # c.endpoint = 'https://fabapi.lexile.com/api/fab/'
59
+ # c.api_verion = '/api/fab/v2'
60
+ # c.endpoint = 'https://fabapi.lexile.com'
57
61
  # c.timeout = '10' #seconds
58
62
  # c.testing = true
59
63
  # end
@@ -84,8 +84,7 @@ module Lexile
84
84
 
85
85
  # Parses a request.body response into a Lexile::Model objects
86
86
  #
87
- def parse( raw_json )
88
- parsed_json = String === raw_json ? JSON.parse(raw_json) : json
87
+ def parse( parsed_json )
89
88
  if parsed_json.has_key?('objects')
90
89
  #this is a multi record and data should contain an array
91
90
  unless parsed_json['objects'].is_a? Array
@@ -1,3 +1,3 @@
1
1
  module Lexile
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -40,12 +40,12 @@ describe Lexile::Api::Books, :vcr => { :cassette_name => "books" } do
40
40
  expect(books).to_not be_nil
41
41
  end
42
42
 
43
- it 'should be array' do
44
- expect(books).to be_an_instance_of( Array )
43
+ it 'first(10) should be array' do
44
+ expect(books.first(10)).to be_an_instance_of( Array )
45
45
  end
46
46
 
47
- it 'length should be > 0' do
48
- expect(books.length).to_not be_zero
47
+ it 'count should be > 0' do
48
+ expect(books.count).to_not be_zero
49
49
  end
50
50
 
51
51
  it 'should be array of Lexile::Book' do
@@ -55,19 +55,19 @@ describe Lexile::Api::Books, :vcr => { :cassette_name => "books" } do
55
55
  end
56
56
 
57
57
  it 'should have id key' do
58
- expect(books[0]).to respond_to(:id)
58
+ expect(books.first).to respond_to(:id)
59
59
  end
60
60
 
61
61
  it 'should have lexile key' do
62
- expect(books[0]).to respond_to(:lexile)
62
+ expect(books.first).to respond_to(:lexile)
63
63
  end
64
64
 
65
65
  it 'should have lexile_display key' do
66
- expect(books[0]).to respond_to(:lexile_display)
66
+ expect(books.first(5)[0]).to respond_to(:lexile_display)
67
67
  end
68
68
 
69
69
  it 'should have pages key' do
70
- expect(books[0]).to respond_to(:pages)
70
+ expect(books.first).to respond_to(:pages)
71
71
  end
72
72
  end
73
73
 
@@ -78,12 +78,12 @@ describe Lexile::Api::Books, :vcr => { :cassette_name => "books" } do
78
78
  expect(books).to_not be_nil
79
79
  end
80
80
 
81
- it 'should be array' do
82
- expect(books).to be_an_instance_of( Array )
81
+ it 'first(10) should return array' do
82
+ expect(books.first(10) ).to be_an_instance_of( Array )
83
83
  end
84
84
 
85
- it 'length should be > 0' do
86
- expect(books.length).to_not be_zero
85
+ it 'count should be > 0' do
86
+ expect(books.count).to_not be_zero
87
87
  end
88
88
 
89
89
  it 'should be array of Lexile::Book' do
@@ -93,19 +93,19 @@ describe Lexile::Api::Books, :vcr => { :cassette_name => "books" } do
93
93
  end
94
94
 
95
95
  it 'should have id key' do
96
- expect(books[0]).to respond_to(:id)
96
+ expect(books.first).to respond_to(:id)
97
97
  end
98
98
 
99
99
  it 'should have lexile key' do
100
- expect(books[0]).to respond_to(:lexile)
100
+ expect(books.first).to respond_to(:lexile)
101
101
  end
102
102
 
103
103
  it 'should have lexile_display key' do
104
- expect(books[0]).to respond_to(:lexile_display)
104
+ expect(books.first).to respond_to(:lexile_display)
105
105
  end
106
106
 
107
107
  it 'should have pages key' do
108
- expect(books[0]).to respond_to(:pages)
108
+ expect(books.first).to respond_to(:pages)
109
109
  end
110
110
  end
111
111