verso 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.gitignore +2 -0
  2. data/README.md +10 -22
  3. data/lib/verso.rb +10 -2
  4. data/lib/verso/base.rb +50 -0
  5. data/lib/verso/cluster.rb +55 -25
  6. data/lib/verso/cluster_list.rb +15 -10
  7. data/lib/verso/correlation_list.rb +30 -40
  8. data/lib/verso/course.rb +106 -43
  9. data/lib/verso/course_list.rb +57 -21
  10. data/lib/verso/credential.rb +94 -20
  11. data/lib/verso/credential_list.rb +30 -15
  12. data/lib/verso/duty_area.rb +23 -10
  13. data/lib/verso/edition_list.rb +18 -10
  14. data/lib/verso/emphasis.rb +26 -12
  15. data/lib/verso/emphasis_list.rb +18 -10
  16. data/lib/verso/examination_list.rb +28 -12
  17. data/lib/verso/extra.rb +34 -32
  18. data/lib/verso/extras_list.rb +28 -12
  19. data/lib/verso/frontmatter.rb +43 -11
  20. data/lib/verso/hash.rb +19 -0
  21. data/lib/verso/http_gettable.rb +31 -0
  22. data/lib/verso/occupation.rb +36 -14
  23. data/lib/verso/occupation_data.rb +35 -14
  24. data/lib/verso/occupation_list.rb +23 -20
  25. data/lib/verso/pathway.rb +32 -14
  26. data/lib/verso/program_area.rb +42 -21
  27. data/lib/verso/program_area_list.rb +15 -11
  28. data/lib/verso/standard.rb +45 -23
  29. data/lib/verso/standards_list.rb +41 -30
  30. data/lib/verso/task.rb +52 -17
  31. data/lib/verso/task_list.rb +40 -17
  32. data/lib/verso/version.rb +1 -1
  33. data/spec/cluster_list_spec.rb +78 -5
  34. data/spec/cluster_spec.rb +106 -9
  35. data/spec/correlation_list_spec.rb +108 -50
  36. data/spec/course_list_spec.rb +112 -23
  37. data/spec/course_spec.rb +321 -127
  38. data/spec/credential_list_spec.rb +83 -52
  39. data/spec/credential_spec.rb +358 -19
  40. data/spec/duty_area_spec.rb +47 -17
  41. data/spec/edition_list_spec.rb +90 -4
  42. data/spec/emphasis_list_spec.rb +75 -11
  43. data/spec/emphasis_spec.rb +37 -21
  44. data/spec/examination_list_spec.rb +146 -20
  45. data/spec/extra_spec.rb +61 -22
  46. data/spec/extras_list_spec.rb +80 -17
  47. data/spec/frontmatter_spec.rb +141 -6
  48. data/spec/hash_spec.rb +49 -0
  49. data/spec/occupation_data_spec.rb +31 -13
  50. data/spec/occupation_list_spec.rb +88 -15
  51. data/spec/occupation_spec.rb +72 -28
  52. data/spec/pathway_spec.rb +47 -27
  53. data/spec/program_area_list_spec.rb +78 -4
  54. data/spec/program_area_spec.rb +70 -22
  55. data/spec/standard_spec.rb +94 -36
  56. data/spec/standards_list_spec.rb +130 -36
  57. data/spec/task_list_spec.rb +160 -51
  58. data/spec/task_spec.rb +120 -33
  59. data/verso.gemspec +3 -1
  60. metadata +41 -17
  61. data/lib/verso/http_get.rb +0 -9
  62. data/lib/verso/sol_correlation_list.rb +0 -53
  63. data/spec/sol_correlation_list_spec.rb +0 -74
@@ -1,36 +1,72 @@
1
1
  module Verso
2
- class CourseList
2
+ # Search Verso courses by :text, :cluster, :program_area, :code, :edition,
3
+ # or any combination and get back an Array-like collection of
4
+ # {Verso::Course} objects.
5
+ #
6
+ # @see http://api.cteresource.org/docs/courses
7
+ #
8
+ # @example Search by text
9
+ # courses = Verso::CourseList.new(:text => "golf") # => <Verso::CourseList:0x007fa5a10bbb68 @attrs={:text=>"golf"}>
10
+ # courses.first.title # => "Turf Grass Applications, Advanced"
11
+ #
12
+ # @example Search by cluster
13
+ # course = Verso::CourseList.new(:cluster => "Information Technology).first
14
+ # course.title # => "Computer Applications"
15
+ #
16
+ # @example Search by program area
17
+ # course = Verso::CourseList.new(:program_area => "Career Connections").last
18
+ # course.title # => "Career Investigation Phase I"
19
+ #
20
+ # @example Search by code
21
+ # courses = Verso::CourseList.new(:code => "6320") # => <Verso::CourseList:0x007fa5a1f27a08 @attrs={:code=>"6320"}>
22
+ # courses.first # => <Verso::Course:0x007fa5a1f3e5c8 @attrs={:duration=>36, :edition=>"2012", :code=>"6320" . . . }>
23
+ # courses.first.code # => "6320"
24
+ #
25
+ # @example Search by edition
26
+ # all_2012 = Verso::CourseList.new(:edition => "2012")
27
+ #
28
+ # @example Search by combination
29
+ # courses = Verso::CourseList.new(:text => "internet", :cluster => "Marketing") # => <Verso::CourseList:0x007fa5a19b6c90 @attrs={ . . . }>
30
+ # courses.count # => 1
31
+ #
32
+ # @example An empty search returns an empty list
33
+ # courses = Verso::CourseList.new
34
+ # courses.count # => 0
35
+ #
36
+ # @overload initialize(attrs={})
37
+ # @option attrs [String] :code Course code
38
+ # @option attrs [String] :edition Edition year
39
+ # @option attrs [String] :text Free text
40
+ # @option attrs [String] :cluster Cluster title
41
+ # @option attrs [String] :program_area Program Area title
42
+ class CourseList < Verso::Base
3
43
  include Enumerable
4
- include HTTPGet
44
+ include HTTPGettable
45
+ extend Forwardable
46
+ def_delegators :courses, :[], :each, :empty?, :last, :length
5
47
 
6
- def initialize(raw_query)
7
- @q_uri = Addressable::URI.new(
8
- :path => '/courses',
9
- :query_values => raw_query.
10
- select { |k, v| v }.
11
- reject { |k, v| v.to_s.empty? }
12
- )
13
- end
48
+ private
14
49
 
15
50
  def courses
16
- @courses ||= if @q_uri.query_values.values.any?
17
- JSON.parse(http_get(@q_uri.request_uri))["courses"].
18
- collect { |c| Course.new(c) }
51
+ @courses ||= if q_uri.query_values.values.any?
52
+ get_attr(:courses).collect { |c| Course.new(c) }
19
53
  else
20
54
  []
21
55
  end
22
56
  end
23
57
 
24
- def each &block
25
- courses.each &block
26
- end
27
-
28
- def last
29
- courses[-1]
58
+ def q_uri
59
+ Addressable::URI.new(
60
+ :path => '/courses',
61
+ :query_values => attrs.
62
+ reject { |k, v| k == :courses }.
63
+ select { |k, v| v }.
64
+ reject { |k, v| v.to_s.empty? }
65
+ )
30
66
  end
31
67
 
32
- def empty?
33
- courses.empty?
68
+ def path
69
+ q_uri.request_uri
34
70
  end
35
71
  end
36
72
  end
@@ -1,34 +1,108 @@
1
1
  module Verso
2
- class Credential
3
- include HTTPGet
2
+ # Credential Resource
3
+ #
4
+ # The usual way to get a Credential would be to use {Verso::CredentialList}
5
+ # or to get one from a related object, such as a {Verso::Course} object.
6
+ #
7
+ # @see http://api.cteresource.org/docs/credentials/credential
8
+ #
9
+ # @!attribute [r] admin_notes
10
+ # @return [String] HTML-formatted test administration notes
11
+ # @!attribute [r] amt_seal
12
+ # @return [Booelean] Advanced Math and Technology seal
13
+ # @!attribute [r] contact_info
14
+ # @return [String] Contractor contact information
15
+ # @!attribute [r] cost
16
+ # @return [String] Cost
17
+ # @!attribute [r] cte_seal
18
+ # @return [Boolean] CTE seal
19
+ # @!attribute [r] description
20
+ # @return [String] HTML-formatted text describing the credential.
21
+ # @!attribute [r] has_ancestor
22
+ # @return [Boolean] Did this credential exist in an earlier edition?
23
+ # @!attribute [r] how_to_earn_it
24
+ # @return [String] HTML-formatted text about how to earn it.
25
+ # @!attribute [r] id
26
+ # @return [Fixnum] Credential id
27
+ # @!attribute [r] items
28
+ # @return [String] Number of test items
29
+ # @!attribute [r] passing_score
30
+ # @return [Sring] Passing score
31
+ # @!attribute [r] pretest
32
+ # @return [Boolean,nil] Is a pre-test, study guide, or blueprint available?
33
+ # @!attribute [r] proctor
34
+ # @return [String] Test examiner/proctor
35
+ # @!attribute [r] program_area
36
+ # @return [String] Title of associated program area
37
+ # @!attribute [r] retired
38
+ # @return [Boolean] Is this credential slated for deletion?
39
+ # @!attribute [r] site
40
+ # @return [String] Allowed testing site
41
+ # @!attribute [r] time
42
+ # @return [String] Time allowed
43
+ # @!attribute [r] title
44
+ # @return [String] Credential title
45
+ # @!attribute [r] type
46
+ # @return ['Certification','License'] Credential type
47
+ # @!attribute [r] verified_credit
48
+ # @return [Boolean] Verified credit
49
+ #
50
+ # @overload initialize(attrs={})
51
+ # @note Any attributes may be set upon instantiation, using Options Hash.
52
+ # The following are required:
53
+ # @option attrs [Fixnum] :id Credential id *Required*
54
+ class Credential < Verso::Base
55
+ include HTTPGettable
56
+ attr_reader :admin_notes, :amt_seal, :contact_info, :cost, :cte_seal,
57
+ :description, :has_ancestor, :how_to_earn_it, :id, :items, :passing_score,
58
+ :pretest, :proctor, :program_area, :retired, :site, :time, :title, :type,
59
+ :verified_credit
60
+ alias amt_seal? amt_seal
61
+ alias cte_seal? cte_seal
62
+ alias has_ancestor? has_ancestor
63
+ alias retired? retired
64
+ alias verified_credit? verified_credit
4
65
 
5
- def initialize(opts)
6
- @raw_credential = opts
66
+ # VDOE contacts, each responding to #name, #email, and #phone, all Strings.
67
+ #
68
+ # @return [Array] VDOE contacts
69
+ def contacts
70
+ @contacts ||= get_attr(:contacts).collect { |c| OpenStruct.new(c) }
7
71
  end
8
72
 
9
- def method_missing(mname)
10
- if @raw_credential[mname.to_s].nil?
11
- @raw_credential.merge!(
12
- JSON.parse(http_get("/credentials/#{id}"))["credential"]
13
- )
14
- end
15
- @raw_credential[mname.to_s]
73
+ # @return [String] Contractor name
74
+ def contractor_name
75
+ get_attr(:contractor_name).to_s
16
76
  end
17
77
 
18
- def source
19
- @source ||= OpenStruct.new(method_missing(:source))
78
+ # @return [String] Details
79
+ def details
80
+ get_attr(:details).to_s # #to_s b/c API sometimes returns nil
20
81
  end
21
82
 
22
- def details
23
- @details ||= if @raw_credential.has_key?("details")
24
- @raw_credential["details"]
25
- else
26
- method_missing(:details)
27
- end.to_s
83
+ # Source. Responds to #title, #url, and #contact_info. All are Strings or
84
+ # nil. The last is HTML-formatted.
85
+ #
86
+ # @return [OpenStruct] Source
87
+ def source
88
+ # force update if we only have part of source
89
+ attrs.merge!(fetch) unless attrs[:source] && attrs[:source].has_key?(:url)
90
+ OpenStruct.new(get_attr(:source))
28
91
  end
29
92
 
93
+ # @return [Array] Collection of related {Verso::Course} objects
30
94
  def related_courses
31
- method_missing(:related_courses).collect { |rc| Course.new(rc) }
95
+ @courses ||= get_attr(:related_courses).collect { |rc| Course.new(rc) }
96
+ end
97
+
98
+ private
99
+
100
+ def path
101
+ "/credentials/#{id}"
102
+ end
103
+
104
+ def fetch
105
+ super[:credential]
32
106
  end
33
107
  end
34
108
  end
@@ -1,28 +1,43 @@
1
1
  module Verso
2
- class CredentialList
2
+ # Credential list resource
3
+ #
4
+ # Search for {Verso::Credential} objects using free text, or get back the
5
+ # list of all of them.
6
+ #
7
+ # @see http://api.cteresource.org/docs/credentials
8
+ #
9
+ # @example All
10
+ # creds = Verso::CredentialList.new # => everything
11
+ # creds.first # => <Verso::Credential:0x007fb1a39e4038 . . . >
12
+ #
13
+ # @example Search
14
+ # creds = Verso::CredentialList.new(:text => "nocti")
15
+ # creds.first.source.title # => "National Occupational Competency Testing Institute (NOCTI)"
16
+ #
17
+ # @overload initialize(attrs={})
18
+ # @option attrs [String] :text Free text
19
+ class CredentialList < Verso::Base
3
20
  include Enumerable
4
- include HTTPGet
21
+ include HTTPGettable
22
+ extend Forwardable
23
+ def_delegators :credentials, :[], :each, :empty?, :last, :length
5
24
 
6
- attr_reader :credentials
25
+ private
7
26
 
8
- def initialize(opts={})
9
- @q_uri = Addressable::URI.new(:path => '/credentials')
10
- @q_uri.query_values = opts unless opts[:text].to_s.empty?
11
- @credentials = JSON.parse(http_get(@q_uri.request_uri))["credentials"].
27
+ def credentials
28
+ @credentials ||= get_attr(:credentials).
12
29
  collect { |c| Credential.new(c) }.
13
30
  sort_by { |c| c.title }
14
31
  end
15
32
 
16
- def each &block
17
- credentials.each &block
33
+ def path
34
+ q_uri ||= Addressable::URI.new(:path => '/credentials')
35
+ q_uri.query_values = { :text => text } unless text.empty?
36
+ q_uri.request_uri
18
37
  end
19
38
 
20
- def last
21
- credentials[-1]
22
- end
23
-
24
- def empty?
25
- credentials.empty?
39
+ def text
40
+ attrs[:text] ? attrs[:text] : ''
26
41
  end
27
42
  end
28
43
  end
@@ -1,16 +1,29 @@
1
1
  module Verso
2
- class DutyArea
3
- attr_reader :title, :context
4
-
5
- def initialize(raw_da, context)
6
- @context = context
7
- @title = raw_da["title"]
8
- @raw_tasks = raw_da["tasks"]
9
- end
2
+ # Duty Area
3
+ #
4
+ # A group of tasks in a {Verso::TaskList}.
5
+ #
6
+ # @see http://api.cteresource.org/docs/courses/course/tasks
7
+ #
8
+ # @!attribute [r] code
9
+ # @return [String] Course code
10
+ # @!attribute [r] edition
11
+ # @return [String] Course edition year
12
+ # @!attribute [r] title
13
+ # @return [String] Duty Area title
14
+ #
15
+ # @note A DutyArea is created for you by {Verso::TaskList}. It corresponds
16
+ # to a portion of the Task List resource. You should never need to
17
+ # instantiate one yourself.
18
+ class DutyArea < Verso::Base
19
+ attr_reader :code, :edition, :title
10
20
 
21
+ # Tasks within this Duty Area
22
+ #
23
+ # @return [Array] {Verso::Task} objects
11
24
  def tasks
12
- @tasks ||= @raw_tasks.collect do |t|
13
- Task.new(t.merge("code" => context.code, "edition" => context.edition))
25
+ @tasks ||= get_attr(:tasks).collect do |t|
26
+ Task.new(t.merge(:code => code, :edition => edition))
14
27
  end
15
28
  end
16
29
  end
@@ -1,19 +1,27 @@
1
1
  module Verso
2
- class EditionList
2
+ # Edition List resource
3
+ #
4
+ # A collection of Edition proxies that respond to #year, returning a string
5
+ # year like '2012'.
6
+ #
7
+ # @example Get a list
8
+ # editions = Verso::EditionList.new
9
+ # editions.first.year => # "2012"
10
+ #
11
+ class EditionList < Verso::Base
3
12
  include Enumerable
4
- include HTTPGet
13
+ include HTTPGettable
14
+ extend Forwardable
15
+ def_delegators :editions, :[], :each, :empty?, :last, :length
5
16
 
6
- def editions
7
- @editions ||= JSON.parse(http_get('/editions/'))["editions"].
8
- collect { |e| OpenStruct.new(e) }
9
- end
17
+ private
10
18
 
11
- def each &block
12
- editions.each &block
19
+ def editions
20
+ @editions ||= get_attr(:editions).collect { |e| OpenStruct.new(e) }
13
21
  end
14
22
 
15
- def last
16
- editions[-1]
23
+ def path
24
+ "/editions/"
17
25
  end
18
26
  end
19
27
  end
@@ -1,21 +1,35 @@
1
1
  module Verso
2
- class Emphasis
3
- include HTTPGet
2
+ # Academic Emphasis resource
3
+ #
4
+ # @see http://api.cteresource.org/docs/academics/emphasis
5
+ #
6
+ # @!attribute [r] id
7
+ # @return [Fixnum] Academic Emphasis id
8
+ # @!attribute [r] title
9
+ # @return Academic Emphasis title
10
+ #
11
+ # @overload initialize(attrs={})
12
+ # @note Any attributes may be set upon instantiation, using Options Hash.
13
+ # The following are required:
14
+ # @option attrs [Fixnum] :id Academic Emphasis id *Required*
15
+ class Emphasis < Verso::Base
16
+ include HTTPGettable
17
+ attr_reader :id, :title
4
18
 
5
- def initialize(raw_emphasis)
6
- @raw_emphasis = raw_emphasis
19
+ # @return [Array] Collection of related {Verso::OccupationData} objects
20
+ def occupation_data
21
+ @occupation_data ||= get_attr(:occupation_data).
22
+ collect { |od| OccupationData.new(od) }
7
23
  end
8
24
 
9
- def method_missing(mname)
10
- if !@raw_emphasis.has_key?(mname.to_s)
11
- @raw_emphasis = JSON.parse(http_get("/academics/#{id}"))["emphasis"]
12
- end
13
- @raw_emphasis[mname.to_s]
25
+ private
26
+
27
+ def fetch
28
+ super[:emphasis]
14
29
  end
15
30
 
16
- def occupation_data
17
- @occupation_data ||= method_missing(:occupation_data).
18
- collect { |od| OccupationData.new(od) }
31
+ def path
32
+ "/academics/#{id}"
19
33
  end
20
34
  end
21
35
  end
@@ -1,19 +1,27 @@
1
1
  module Verso
2
- class EmphasisList
2
+ # Academic Emphasis List resource
3
+ #
4
+ # A collection of all {Verso::Emphasis} objects.
5
+ #
6
+ # @see http://api.cteresource.org/docs/academics
7
+ #
8
+ # @example Get a list
9
+ # emphases = Verso::EmphasisList.new # => all of them
10
+ # emphases.first.title # => "Algebra"
11
+ class EmphasisList < Verso::Base
3
12
  include Enumerable
4
- include HTTPGet
13
+ include HTTPGettable
14
+ extend Forwardable
15
+ def_delegators :emphases, :[], :each, :empty?, :last, :length
5
16
 
6
- def emphases
7
- @emphases ||= JSON.parse(http_get('/academics/'))["emphases"].
8
- collect { |em| Emphasis.new(em) }
9
- end
17
+ private
10
18
 
11
- def each &block
12
- emphases.each &block
19
+ def emphases
20
+ @emphases ||= get_attr(:emphases).collect { |em| Emphasis.new(em) }
13
21
  end
14
22
 
15
- def last
16
- emphases[-1]
23
+ def path
24
+ "/academics/"
17
25
  end
18
26
  end
19
27
  end
@@ -1,21 +1,37 @@
1
1
  module Verso
2
- class ExaminationList
2
+ # Examination List resource
3
+ #
4
+ # A collection of Examination stand-in objects that respond to:
5
+ # * #amt_seal @return [Boolean] AMT Seal
6
+ # * #passing_score @return [String] Passing score
7
+ # * #retired @return [Boolean] Slated to be deleted?
8
+ # * #source @return [String] Title of exam source
9
+ # * #title @return [String] Exam title
10
+ # * #verified_credit @return [Booelean] Verified credit
11
+ #
12
+ # The attributes of the Examination stand-ins are similar to
13
+ # {Verso::Credential}.
14
+ #
15
+ # @example Get the list
16
+ # exams = Verso::ExaminationList.new # => everything
17
+ # exams.first.title # => "Advanced Placement Computer Science A"
18
+ #
19
+ # @see http://api.cteresource.org/docs/examinations
20
+ class ExaminationList < Verso::Base
3
21
  include Enumerable
4
- include HTTPGet
22
+ include HTTPGettable
23
+ extend Forwardable
24
+ def_delegators :examinations, :[], :each, :empty?, :last, :length
5
25
 
6
- attr_reader :examinations
26
+ private
7
27
 
8
- def initialize
9
- @examinations = JSON.parse(http_get("/examinations/"))["examinations"].
10
- collect { |e| OpenStruct.new(e) }
28
+ def examinations
29
+ @examinations ||= get_attr(:examinations).
30
+ collect { |e| OpenStruct.new(e) }
11
31
  end
12
32
 
13
- def each &block
14
- examinations.each &block
15
- end
16
-
17
- def last
18
- examinations[-1]
33
+ def path
34
+ "/examinations/"
19
35
  end
20
36
  end
21
37
  end