verso 0.0.2 → 0.0.3

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.
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,38 +1,40 @@
1
1
  module Verso
2
- class Extra
3
- include HTTPGet
4
-
5
- def initialize(raw_extra)
6
- @raw_extra = raw_extra
7
- end
8
-
9
- def code
10
- @raw_extra["code"]
11
- end
12
-
13
- def edition
14
- @raw_extra["edition"]
15
- end
16
-
17
-
18
- def name
19
- @raw_extra["name"]
20
- end
21
-
22
-
23
- def title
24
- @raw_extra["title"]
2
+ # Extra resource
3
+ #
4
+ # An extra (or related material) associated with a Course framework in
5
+ # Verso.
6
+ #
7
+ # @see http://api.cteresource.org/docs/courses/course/extras/extra
8
+ #
9
+ # @!attribute [r] code
10
+ # @return [String] Course code
11
+ # @!attribute [r] edition
12
+ # @return [String] Edition year
13
+ # @!attribute [r] name
14
+ # @return [String] Extra name, used as an identifier and not to
15
+ # be confused with its title, found by {Verso::ExtrasList}
16
+ # @!attribute [r] description
17
+ # @return [String] HTML-formatted Extra description
18
+ # @!attribute [r] title
19
+ # @return [String] Extra title
20
+ #
21
+ # @overload initialize(attrs={})
22
+ # @note Certain attributes are required for instantiation.
23
+ # @option attrs [String] :code Course code *Required*
24
+ # @option attrs [String] :edition Edition year *Required*
25
+ # @option attrs [String] :name Extra name *Required*
26
+ class Extra < Verso::Base
27
+ include HTTPGettable
28
+ attr_reader :code, :description, :edition, :name, :title
29
+
30
+ private
31
+
32
+ def path
33
+ "/courses/#{code},#{edition}/extras/#{name}"
25
34
  end
26
35
 
27
- def description
28
- if @raw_extra["description"].nil?
29
- @raw_extra.merge!(
30
- JSON.parse(
31
- http_get("/courses/#{code},#{edition}/extras/#{name}")
32
- )["extra"]
33
- )
34
- end
35
- @raw_extra["description"]
36
+ def fetch
37
+ super[:extra]
36
38
  end
37
39
  end
38
40
  end
@@ -1,22 +1,38 @@
1
1
  module Verso
2
- class ExtrasList
3
- attr_reader :code, :edition
2
+ # Extras List resource
3
+ #
4
+ # A collection of {Verso::Extra} associated with a {Course} framework.
5
+ #
6
+ # @see http://api.cteresource.org/docs/courses/course/extras
7
+ #
8
+ # @example Get extras for 2012 edition of course 6320
9
+ # extras = Verso::ExtrasList.new(:code => "6320", :edition => "2012")
10
+ #
11
+ # @!attribute [r] code
12
+ # @return [String] Course code
13
+ # @!attribute [r] edition
14
+ # @return [String] Edition year
15
+ #
16
+ # @overload initialize(attrs={})
17
+ # @note Certain attributes are required for instantiation.
18
+ # @option attrs [String] :code Course code *Required*
19
+ # @option attrs [String] :edition Edition year *Required*
20
+ class ExtrasList < Verso::Base
4
21
  include Enumerable
5
- include HTTPGet
22
+ include HTTPGettable
23
+ extend Forwardable
24
+ attr_reader :code, :edition
25
+ def_delegators :extras, :[], :each, :empty?, :last, :length
6
26
 
7
- def initialize(opts)
8
- @code, @edition = opts[:code], opts[:edition]
9
- end
27
+ private
10
28
 
11
29
  def extras
12
- @extras ||= JSON.parse(
13
- http_get("/courses/#{code},#{edition}/extras/")
14
- )["extras"].
15
- collect { |e| Extra.new(e.merge("code" => code, "edition" => edition)) }
30
+ @extras ||= get_attr(:extras).
31
+ collect { |e| Extra.new(e.merge(:code => code, :edition => edition)) }
16
32
  end
17
33
 
18
- def each &block
19
- extras.each &block
34
+ def path
35
+ "/courses/#{code},#{edition}/extras/"
20
36
  end
21
37
  end
22
38
  end
@@ -1,18 +1,50 @@
1
1
  module Verso
2
- class Frontmatter
3
- include HTTPGet
2
+ # Frontmatter resource
3
+ #
4
+ # Frontmatter for {Verso::Course} framework.
5
+ #
6
+ # @see http://api.cteresource.org/docs/courses/course/frontmatter
7
+ #
8
+ # @!attribute [r] acknowledgments_text
9
+ # @return [String] HTML-formatted acknowledgments
10
+ # @!attribute [r] attribution_block
11
+ # @return [String] HTML-formatted attribution
12
+ # @!attribute [r] code
13
+ # @return [String] Course code
14
+ # @!attribute [r] copyright_year
15
+ # @return [String] Copyright year
16
+ # @!attribute [r] developed_by
17
+ # @return [String] HTML-formatted developed-by text
18
+ # @!attribute [r] developed_for
19
+ # @return [String] HTML-formatted developed-for text
20
+ # @!attribute [r] edition
21
+ # @return [String] Edition year
22
+ # @!attribute [r] foreword_text
23
+ # @return [String] HTML-formatted foreword
24
+ # @!attribute [r] introduction_text
25
+ # @return [String] HTML-formatted introduction_text
26
+ # @!attribute [r] notice_block
27
+ # @return [String] HTML formatted notice_block
28
+ #
29
+ # @overload initialize(attrs={})
30
+ # @note Any attributes may be set upon instantiation, using Options Hash.
31
+ # The following are required:
32
+ # @option attrs [String] :code Course code *Required*
33
+ # @option attrs [String] :edition Edition year *Required*
34
+ class Frontmatter < Verso::Base
35
+ include HTTPGettable
36
+ attr_reader :acknowledgments_text, :attribution_block, :code,
37
+ :copyright_year, :developed_by, :developed_for, :edition,
38
+ :foreword_text, :introduction_text, :notice_block
4
39
 
5
- def initialize(opts)
6
- @raw_frontmatter = opts
40
+ private
41
+
42
+ def fetch
43
+ super[:frontmatter]
7
44
  end
8
45
 
9
- def method_missing(mname)
10
- if !@raw_frontmatter.has_key?(mname.to_s)
11
- @raw_frontmatter = JSON.parse(
12
- http_get("/courses/#{@raw_frontmatter['code']},#{@raw_frontmatter['edition']}/frontmatter")
13
- )["frontmatter"]
14
- end
15
- @raw_frontmatter[mname.to_s]
46
+ def path
47
+ "/courses/#{code},#{edition}/frontmatter"
16
48
  end
17
49
  end
18
50
  end
@@ -0,0 +1,19 @@
1
+ class Hash
2
+ def symbolize_nested_keys!
3
+ keys.each do |key|
4
+ self[(key.to_sym rescue key) || key] = if self[key].is_a?(Hash)
5
+ delete(key).symbolize_nested_keys!
6
+ elsif self[key].is_a?(Array)
7
+ delete(key).collect do |i|
8
+ if i.is_a?(Hash)
9
+ i.symbolize_nested_keys!
10
+ end
11
+ i
12
+ end
13
+ else
14
+ delete(key)
15
+ end
16
+ end
17
+ self
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ module Verso
2
+ # Mixin for classes derived from {Verso::Base}. Provides the capability to
3
+ # fetch the JSON resource to update attributes of the class.
4
+ #
5
+ # @abstract Implement a path method that gives the relative path of the
6
+ # corresponding JSON resource.
7
+ module HTTPGettable
8
+ protected
9
+
10
+ # Get an attribute from the attributes store {#attrs}. Fetch and merge
11
+ # first if the attribute store doesn't have the key.
12
+ #
13
+ # @param [Symbol] attr The attribute key
14
+ # @return [Object] The attribute
15
+ def get_attr(attr)
16
+ attrs.merge!(fetch) unless attrs.has_key?(attr)
17
+ super attr
18
+ end
19
+
20
+ # HTTP GET the JSON resource
21
+ # @return [String] JSON resource
22
+ def http_get
23
+ Net::HTTP.get('api.cteresource.org', path, 80)
24
+ end
25
+
26
+ # @return [Hash] Resource hash
27
+ def fetch
28
+ JSON.parse(http_get).symbolize_nested_keys!
29
+ end
30
+ end
31
+ end
@@ -1,25 +1,47 @@
1
1
  module Verso
2
- class Occupation
3
- include HTTPGet
2
+ # Occupation resource
3
+ #
4
+ # An occupation is contained by a Pathway
5
+ #
6
+ # @see http://api.cteresource.org/docs/occupations/occupation
7
+ # @see http://www.careertech.org/career-clusters/clusters-occupations.html
8
+ #
9
+ # @!attribute [r] description
10
+ # @return [String] HTML-formatted Occupation description
11
+ # @!attribute [r] id
12
+ # @return [Fixnum] Occupation ID
13
+ # @!attribute [r] preparations
14
+ # @return [Array] Collection of preparation titles (strings)
15
+ # @!attribute [r] title
16
+ # @return [String] Occupation title
17
+ #
18
+ # @overload initialize(attrs={})
19
+ # @note Any attributes may be set upon instantiation, using Options Hash.
20
+ # The following are required:
21
+ # @option attrs [Fixnum] :id Occupation ID *Required*
22
+ class Occupation < Verso::Base
23
+ include HTTPGettable
24
+ attr_reader :description, :id, :preparations, :title
4
25
 
5
- def initialize(raw_occupation)
6
- @raw_occupation = raw_occupation
26
+ # @return [Verso::Pathway] Pathway that is the parent of this occupation
27
+ def pathway
28
+ @pathway ||= Pathway.new(get_attr(:pathway))
7
29
  end
8
30
 
9
- def method_missing(mname)
10
- if @raw_occupation[mname.to_s].nil?
11
- @raw_occupation = JSON.parse(http_get("/occupations/#{id}"))["occupation"]
12
- end
13
- @raw_occupation[mname.to_s]
31
+ # @return [Array] Collection of related {Verso::Course} objects
32
+ def related_courses
33
+ @related_courses ||= get_attr(:related_courses).
34
+ collect { |c| Course.new(c) }
14
35
  end
15
36
 
16
- def related_courses
17
- @related_courses ||= method_missing(:related_courses).
18
- collect { |c| Course.new(c) }
37
+ private
38
+
39
+ def fetch
40
+ super[:occupation]
19
41
  end
20
42
 
21
- def pathway
22
- @pathway ||= Pathway.new(method_missing(:pathway))
43
+ def path
44
+ "/occupations/#{id}"
23
45
  end
24
46
  end
25
47
  end
@@ -1,30 +1,51 @@
1
1
  module Verso
2
- class OccupationData
3
- def initialize(od)
4
- @raw_od = od
5
- end
6
-
2
+ # Occupation Data
3
+ #
4
+ # A list of occupations grouped by the Cluster/Pathway that contains them.
5
+ # Occupation Data is not an independent resource. It is a component of
6
+ # {Verso::OccupationList}, {Verso::Course}, and {Verso::Emphasis}.
7
+ #
8
+ # @see http://api.cteresource.org/docs/academics/emphasis
9
+ # @see http://api.cteresource.org/docs/courses/course
10
+ # @see http://api.cteresource.org/docs/occupations
11
+ #
12
+ # @note Because an OccupationData object is created for you by other
13
+ # resources you should never need to instantiate one yourself.
14
+ class OccupationData < Verso::Base
15
+ # @return [Verso::Cluster] Cluster (grandparent of occupations)
7
16
  def cluster
8
- @cluster ||= Cluster.new(@raw_od["cluster"])
17
+ @cluster ||= Cluster.new(get_attr(:cluster))
9
18
  end
10
19
 
11
- def pathway
12
- @pathway ||= Pathway.new(@raw_od["pathway"])
20
+ # @return [Array] Collection of {Verso::Occupation} objects
21
+ def occupations
22
+ @occupations ||= get_attr(:occupations).collect { |o| Occupation.new(o) }
13
23
  end
14
24
 
15
- def occupations
16
- @occupations ||= @raw_od["occupations"].
17
- collect { |o| Occupation.new(o) }
25
+ # @return [Verso::Pathway] Pathway (parent of occupations)
26
+ def pathway
27
+ @pathway ||= Pathway.new(get_attr(:pathway))
18
28
  end
19
29
 
30
+ # Find OccupationData by cluster, pathway, and occupation slugs
31
+ #
32
+ # @example Find an OccupationData for an occupation
33
+ # od = Verso::OccupationData.find_by_slugs('finance', 'accounting', 'cost-analyst')
34
+ # od.occupations.count # => 1
35
+ # od.occupations.first.title # => 'Cost Analyst'
36
+ #
37
+ # @param [String] cslug Cluster slug
38
+ # @param [String] pslug Pathway slug
39
+ # @param [String] slug Occupation slug
40
+ # @return [Verso::OccupationData,nil] Containing only one Occupation
20
41
  def self.find_by_slugs(cslug, pslug, slug)
21
42
  cluster = ClusterList.new.find { |c| c.title.parameterize == cslug }
22
43
  pathway = cluster.pathways.find { |p| p.title.parameterize == pslug }
23
44
  occupation = pathway.occupations.find { |o| o.title.parameterize == slug }
24
45
  OccupationData.new(
25
- { "cluster" => { "title" => cluster.title },
26
- "pathway" => { "title" => pathway.title },
27
- "occupations" => [{ "title" => occupation.title }] }
46
+ { :cluster => { :title => cluster.title },
47
+ :pathway => { :title => pathway.title },
48
+ :occupations => [{ :title => occupation.title }] }
28
49
  )
29
50
  end
30
51
  end
@@ -1,32 +1,35 @@
1
1
  module Verso
2
- class OccupationList
2
+ # Occupation list resource
3
+ #
4
+ # Search {Verso::Occupation} objects using free text. Result is a collection
5
+ # of {Verso::OccupationData} objects containing relevant {Verso::Occupation}
6
+ # objects.
7
+ #
8
+ # @see http://api.cteresource.org/docs/occupations
9
+ #
10
+ # @example Search by free text
11
+ # ods = Verso::OccupationList.new(:text => "golf") # => golf-related ODs
12
+ #
13
+ # @overload initialize(attrs={})
14
+ # @option attrs [String] :text Free text
15
+ class OccupationList < Verso::Base
3
16
  include Enumerable
4
- include HTTPGet
17
+ include HTTPGettable
18
+ extend Forwardable
19
+ def_delegators :occupations, :[], :each, :empty?, :last, :length
5
20
 
6
- def initialize(raw_query={})
7
- @q_uri = Addressable::URI.new(
8
- :path => '/occupations',
9
- :query_values => raw_query
10
- )
11
- end
21
+ private
12
22
 
13
23
  def occupations
14
- @occupations ||= JSON.
15
- parse(http_get(@q_uri.request_uri))["occupation_data"].
24
+ return [] if attrs[:text].to_s.empty?
25
+ @occupations ||= get_attr(:occupation_data).
16
26
  collect { |o| OccupationData.new(o) }.
17
27
  sort_by { |o| [o.cluster.title, o.pathway.title] }
18
28
  end
19
29
 
20
- def each &block
21
- occupations.each &block
22
- end
23
-
24
- def last
25
- occupations[-1]
26
- end
27
-
28
- def empty?
29
- occupations.empty?
30
+ def path
31
+ @path ||= Addressable::URI.new(:path => '/occupations',
32
+ :query_values => attrs).request_uri
30
33
  end
31
34
  end
32
35
  end
@@ -1,25 +1,43 @@
1
1
  module Verso
2
- class Pathway
3
- include HTTPGet
2
+ # Pathway Resource
3
+ #
4
+ # @see http://api.cteresource.org/docs/pathways/pathway
5
+ # @see http://www.careertech.org/career-clusters/clusters-occupations.html
6
+ #
7
+ # @!attribute [r] description
8
+ # @return [String] HTML-formatted Pathway description
9
+ # @!attribute [r] id
10
+ # @return [Fixnum] Pathway id
11
+ # @!attribute [r] title
12
+ # @return [String] Pathway title
13
+ #
14
+ # @overload initialize(attrs={})
15
+ # @note Any attributes may be set upon instantiation, using Options Hash.
16
+ # The following are required:
17
+ # @option attrs [Fixnum] :id Pathway id *Required*
18
+ class Pathway < Verso::Base
19
+ include HTTPGettable
20
+ attr_reader :description, :id, :title
4
21
 
5
- def initialize(raw_pathway)
6
- @raw_pathway = raw_pathway
7
- end
8
-
9
- def method_missing(mname)
10
- if @raw_pathway[mname.to_s].nil?
11
- @raw_pathway = JSON.parse(http_get("/pathways/#{id}"))["pathway"]
12
- end
13
- @raw_pathway[mname.to_s]
22
+ # @return [Verso::Cluster] Parent Cluster
23
+ def cluster
24
+ @cluster ||= Cluster.new(get_attr(:cluster))
14
25
  end
15
26
 
27
+ # @return [Array] Children {Verso::Occupation} objects
16
28
  def occupations
17
- @occupations ||= method_missing(:occupations).
29
+ @occupations ||= get_attr(:occupations).
18
30
  collect { |o| Occupation.new(o) }
19
31
  end
20
32
 
21
- def cluster
22
- @cluster ||= Cluster.new(method_missing(:cluster))
33
+ private
34
+
35
+ def fetch
36
+ super[:pathway]
37
+ end
38
+
39
+ def path
40
+ "/pathways/#{id}"
23
41
  end
24
42
  end
25
43
  end