verso 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d77111f7d6014a8e8c6895adb5fce355dec560ae
4
- data.tar.gz: 5358aaa41b752dec7dfacb6f041c920c5c00ae84
3
+ metadata.gz: 6cc8157c300f2bb76447aea7364fcc06456a837a
4
+ data.tar.gz: 7047e6972fb757fa0d37efc6658141051d08ccd2
5
5
  SHA512:
6
- metadata.gz: 8bc3d7d4ab6f4bf5b29fb4d314c50c51e67a90eb62819ff905885abd1382cc03e678a1124ff80416099cfc2fd7af2c97e4602942630dcac64885678265162729
7
- data.tar.gz: bf663a9bf8f9a497a87a9cb637753a932b774390665e662698cce90dc3ac21f3f8b67f38d95bac9922a56aa180b41fc0b5d9fa1a692674d83fab2939af42c9cb
6
+ metadata.gz: 296524656f995cd3119a199db8033dc0288850fc149eb2685b5cbd37dbe04e1e0c09513e16765c9ea0df8c5a3b4770380c907147cb7d54e0165ba7db6ad85328
7
+ data.tar.gz: 5a8032ba1ca5aafc5b7f9cd86c75381317c966ad4c5f6661a56d12143651255ffc6b9fd3c88d83487bb37363e3034677b836d10491b801f32f66ebe91c575e5e
data/README.md CHANGED
@@ -18,7 +18,7 @@ The verso gem has been tested with Ruby 2.0.0, 1.9.3, and 1.8.7.
18
18
 
19
19
  ## Quick Start
20
20
 
21
- The wrapper should make a great starting pointing for getting course,
21
+ The wrapper should make a great starting point for getting course,
22
22
  curriculum, and occupation data out of Verso. The classes available in
23
23
  lib/verso correspond to the resources described in the [API
24
24
  documentation](http://api.cteresource.org/docs). The usual points of entry
@@ -65,6 +65,91 @@ Search for Occupations, get back lists of "occupation data," i.e., a list of lis
65
65
  creds.first.title # => "Computer Programming (NOCTI)"
66
66
  creds.first.related_courses.last # => "Programming, Advanced"
67
67
 
68
+ ## New! verso-mt command line tool
69
+
70
+ verso-mt is a command line tool for generating the simpler sorts of CSV reports
71
+ from the CTE Resource Center Web API data. If you need to work on *collections*
72
+ of related resources -- all the occupations related to a course, say, or all
73
+ the courses related to a course, or all the credentials related to a course --
74
+ then verso-mt won't help. You'll need to write a script. But if you only need a
75
+ report from attributes on courses, credentials, or occupations, verso-mt
76
+ totally makes this easy. It will even let you reach into related objects -- an
77
+ occupation's pathway, say, or a credential's source.
78
+
79
+ You can see a help message by typing `verso-mt -h`. Three sorts of resources
80
+ can be fetched: course, credential, and occupation. Course is the default. Use
81
+ the -q option to specify query parameters. The parameters permissible are
82
+ discussed in the API documentation for CourseList, CredentialList, and
83
+ OccupationList. Separate the parameter from its value with a colon (:) and
84
+ separate multiple parameters with a plus (+), e.g. text:foo+edition:2013.
85
+ Filters, specified with the -f option are formed the same way, but are used by
86
+ verso-mt to filter out results after they're fetched from the server, based on
87
+ a fuzzy match against the specified attribute. Specify the columns you wish to
88
+ see in your CSV report with the -c option and a comma-separated list of
89
+ attributes. You can use dot notation to reach into a related object. E.g., `-c
90
+ title,source.title` could be used to get the title and source title for a list
91
+ of credentials.
92
+
93
+ Here are some examples:
94
+
95
+ ### Similar to examples/copyright_year.rb
96
+
97
+ In this example, we do not specify the resource. It defaults to course.
98
+
99
+ verso-mt -c title,code,frontmatter.copyright_year,related_resources
100
+
101
+ ### similar to examples/course_notes.rb
102
+
103
+ verso-mt -c code,title,notes
104
+
105
+ ### similar to examples/cpo.rb
106
+
107
+ Here we use the '-q' query parameter. You can send it any parameter mentioned
108
+ in the API documentation for the corresponding resource. Here we are sending a
109
+ wildcard (i.e., everything) in the text parameter for occupations.
110
+
111
+ verso-mt -r occupation -q text:* -c title,pathway.title,pathway.cluster.title
112
+
113
+ ### similar to examples/credential_cost.rb
114
+
115
+ verso-mt -r credential -c title,cost
116
+
117
+ ### similar to examples/credential_sources.rb
118
+
119
+ Note in this example, we are reaching into the source, a related object, using
120
+ dot notation.
121
+
122
+ verso-mt -r credential -c title,source.title,contractor_name
123
+
124
+ ### equivalent to examples/hours.rb
125
+
126
+ Note in this example, we are using '-f' the filtering option. We ask it to
127
+ filter out only courses that have 140 hours.
128
+
129
+ verso-mt -f hours:140 -c title,code,hours
130
+
131
+ ### equivalent to examples/hs_and_ms.rb
132
+
133
+ Note we are specifying two filters here.
134
+
135
+ verso-mt -f is_hs?:true+is_ms?:true
136
+
137
+ ### equivalent to examples/hs_v_ms.rb
138
+
139
+ verso-mt -c title,code,is_ms?,is_hs?
140
+
141
+ ### equivalent to examples/passing_score.rb
142
+
143
+ verso-mt -r credential -c title,source.title,passing_score
144
+
145
+ ### all the courses related to 'energy' in 2013 edition with 'technology' in title
146
+
147
+ verso-mt -r course -q text:energy+edition:2013 -f title:technology -c title,code,edition
148
+
149
+ ### search credentials for 'web' and return all where source title matches nocti
150
+
151
+ verso-mt -r credential -q text:web -f source.title:nocti -c title,source.title
152
+
68
153
  ## Additional Documentation
69
154
 
70
155
  * [http://api.cteresource.org/docs](http://api.cteresource.org/docs)
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env ruby
2
+ require 'csv'
3
+ require 'optparse'
4
+ require 'verso'
5
+
6
+ module Verso
7
+ module ChainableSend
8
+ # takes a string of dot-separated method names and recursively calls
9
+ # Object#send with each
10
+ def chained_send(chain)
11
+ messages = chain.split('.')
12
+ if messages.length == 1
13
+ respond_to?(chain) ? send(chain) : ''
14
+ else
15
+ send(messages.first).
16
+ extend(Verso::ChainableSend).
17
+ chained_send(messages.slice(1, messages.length).join('.'))
18
+ end
19
+ end
20
+ end
21
+
22
+ class OccupationList
23
+ private
24
+
25
+ # confusingly, OccupationList is actually a list of OccupationData obj's
26
+ # monkey patch so it behaves as expected for this script
27
+ alias_method :occupations_datas, :occupations
28
+ def occupations
29
+ occupations_datas.flat_map { |od| od.occupations }
30
+ end
31
+ end
32
+
33
+ class OptionBucket
34
+ attr_accessor :resource, :params, :filters, :columns
35
+ def initialize(opts={})
36
+ @resource = opts[:resource] || 'course'
37
+ @params = opts[:params] || {}
38
+ @filters = opts[:filters] || {}
39
+ @columns = opts[:columns] || ['title', 'code']
40
+ fill!(opts[:argv] || ARGV)
41
+ end
42
+
43
+ private
44
+
45
+ def fill!(argv)
46
+ parser = OptionParser.new do |opts|
47
+ opts.banner = 'Usage: verso [options]'
48
+
49
+ opts.on('-h', '--helper', 'Show this message.') do
50
+ puts opts
51
+ exit
52
+ end
53
+
54
+ opts.on('-r', '--resource RES', ['course', 'credential', 'occupation'],
55
+ 'API resource list to get',
56
+ 'One of: course, credential, occupation.') do |res|
57
+ @resource = res
58
+ end
59
+
60
+ opts.on(
61
+ '-c', '--columns COLS', Array,
62
+ 'Comma-separated list of resource attributes to display.') do |attrs|
63
+ @columns = attrs
64
+ end
65
+
66
+ opts.accept kv_pairs = Object.new do |val|
67
+ pairs = val.split('+')
68
+ raise OptionParser::InvalidArgument unless pairs.all? do |i|
69
+ i =~ /^[\w\s.\?]+:[\w\s.\*]+$/
70
+ end
71
+ pairs.inject({}) do |h, pair|
72
+ h[pair.split(':').first] = pair.split(':').last
73
+ h
74
+ end
75
+ end
76
+
77
+ opts.on(
78
+ '-f', '--filters FILTERS', kv_pairs,
79
+ 'Plus-separated list of colon-separated PROP:VALUE pairs.') do |f|
80
+ @filters = f
81
+ end
82
+
83
+ opts.on(
84
+ '-q', '--query PARAMS', kv_pairs,
85
+ 'Plus-separated list of colon-separated PARAM:VALUE pairs.',
86
+ 'Parameters should correspond to those in the resource docs.') do |p|
87
+ @params = p
88
+ end
89
+ end
90
+ parser.parse!(argv)
91
+ end
92
+ end
93
+
94
+ class MultiTool
95
+ attr_reader :options
96
+ def initialize(options)
97
+ @options = options
98
+ end
99
+
100
+ def klass
101
+ eval("Verso::#{options.resource.capitalize}List")
102
+ end
103
+
104
+ def resources
105
+ klass.new(options.params).collect do |r|
106
+ r.extend(Verso::ChainableSend)
107
+ end
108
+ end
109
+
110
+ def filtered_resources
111
+ resources.select do |resource|
112
+ options.filters.all? do |k, v|
113
+ resource.chained_send(k).to_s =~ Regexp.new(v, Regexp::IGNORECASE)
114
+ end
115
+ end
116
+ end
117
+
118
+ def run(&block)
119
+ block.call(options, filtered_resources)
120
+ end
121
+ end
122
+ end
123
+
124
+ begin
125
+ options = Verso::OptionBucket.new
126
+ rescue OptionParser::InvalidArgument => e
127
+ puts e
128
+ exit(1)
129
+ end
130
+
131
+ mt = Verso::MultiTool.new(options)
132
+ mt.run do |options, resources|
133
+ puts CSV.generate_line(
134
+ options.columns.
135
+ collect { |c| "#{options.resource.capitalize} #{c.capitalize}" }
136
+ )
137
+ resources.each do |resource|
138
+ puts CSV.generate_line(
139
+ options.columns.collect { |col| resource.chained_send(col) }
140
+ )
141
+ end
142
+ end
@@ -0,0 +1,17 @@
1
+ # usage: ruby associated_with.rb 'Title of a Standard'
2
+ #
3
+ # e.g., ruby associated_with.rb 'Science' # => all courses associated with
4
+ # the Science standards body.
5
+
6
+ require 'csv'
7
+ require 'verso'
8
+
9
+ standard = ARGV[0] || 'Science'
10
+
11
+ puts CSV.generate_line(%w{ Code Title }) + "\n"
12
+
13
+ Verso::CourseList.new.each do |c|
14
+ if c.standards.find { |c| c.title == standard }
15
+ puts CSV.generate_line([c.code, c.title])
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ # usage: ruby ceop.rb
2
+ #
3
+ # dumps CSV list of courses wth cluster, pathway, occupation information in CSV
4
+ # format.
5
+
6
+ require 'csv'
7
+ require 'verso'
8
+
9
+ puts CSV.generate_line(%w{ Title Code Edition Cluster Pathway Occupation })
10
+
11
+ Verso::CourseList.new.each do |c|
12
+ c.occupation_data.each do |od|
13
+ od.occupations.each do |occupation|
14
+ puts CSV.generate_line(
15
+ [c.title, c.code, c.edition, od.cluster.title,
16
+ od.pathway.title, occupation.title]
17
+ )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ # usage: ruby copyright_year.rb
2
+ #
3
+
4
+ require 'csv'
5
+ require 'verso'
6
+
7
+ puts CSV.generate_line(
8
+ %w(Program\ Area Title Code Copyright Related\ Resources)
9
+ )
10
+ courses = Verso::CourseList.new
11
+ courses.sort_by { |course| course.title }.each do |course|
12
+ course.attrs[:program_areas].each do |pa|
13
+ puts CSV.generate_line [
14
+ pa,
15
+ course.title,
16
+ course.code,
17
+ course.frontmatter ? course.frontmatter.copyright_year : '',
18
+ course.related_resources.join(', ')
19
+ ]
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ # usage: ruby course_notes.rb
2
+
3
+ require 'csv'
4
+ require 'verso'
5
+
6
+ Verso::CourseList.new.each do |course|
7
+ unless course.notes.to_s.empty?
8
+ puts CSV.generate_line([course.code, course.title, course.notes])
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ # usage: ruby cpo.rb
2
+ require 'csv'
3
+ require 'verso'
4
+
5
+ puts CSV.generate_line(%w(Occupation Pathway Cluster))
6
+ ods = Verso::OccupationList.new(:text => '*')
7
+ ods.each do |od|
8
+ od.occupations.each do |o|
9
+ puts CSV.generate_line [o.title, od.pathway.title, od.cluster.title]
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ # usage: ruby credential_cost.rb
2
+
3
+ require 'csv'
4
+ require 'verso'
5
+
6
+ puts CSV.generate_line(['Title', 'cost'])
7
+ Verso::CredentialList.new.each do |cred|
8
+ puts CSV.generate_line([cred.title, cred.cost])
9
+ end
@@ -0,0 +1,10 @@
1
+ # usage: ruby credential_sources.rb
2
+ #
3
+
4
+ require 'csv'
5
+ require 'verso'
6
+
7
+ puts CSV.generate_line(%w(Credential Source Contractor))
8
+ Verso::CredentialList.new.each do |cred|
9
+ puts CSV.generate_line([cred.title, cred.source.title, cred.contractor_name])
10
+ end
@@ -0,0 +1,25 @@
1
+ # usage: ruby credentials.rb
2
+
3
+ require 'csv'
4
+ require 'verso'
5
+
6
+ puts CSV.generate_line(
7
+ %w{ Title Description Source Contractor Related\ Courses }
8
+ )
9
+
10
+ Verso::CredentialList.new.each do |cred|
11
+ puts CSV.generate_line(
12
+ [cred.title,
13
+ cred.description.
14
+ gsub(/<\/?[^>]*>/, "").
15
+ strip.
16
+ gsub(/\r\n/, " | ").
17
+ gsub(/&[a-zA-Z]+;/, " "),
18
+ cred.source.title,
19
+ cred.contractor_name,
20
+ cred.
21
+ related_courses.
22
+ collect { |c| "#{c.title} (#{c.code})" }.
23
+ join('; ')]
24
+ )
25
+ end
@@ -0,0 +1,12 @@
1
+ # usage: ruby hours.rb NN
2
+
3
+ require 'csv'
4
+ require 'verso'
5
+
6
+ hours = ARGV[0].to_i
7
+ Verso::CourseList.new.
8
+ select { |c| c.hours == hours }.
9
+ sort_by { |c| c.title }.
10
+ each do |course|
11
+ puts CSV.generate_line [course.title, course.code]
12
+ end
@@ -0,0 +1,9 @@
1
+ # usage: ruby hs_and_ms.rb
2
+
3
+ require 'verso'
4
+
5
+ Verso::CourseList.new.each do |course|
6
+ if course.is_hs? && course.is_ms?
7
+ puts "#{course.title} (#{course.code})"
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ # usage: ruby hs_v_ms.rb
2
+
3
+ require 'csv'
4
+ require 'verso'
5
+
6
+ Verso::CourseList.new.sort_by { |c| c.title + c.code }.each do |course|
7
+ puts CSV.generate_line(
8
+ ["#{course.title} (#{course.code})",
9
+ course.is_ms? && !course.is_hs? ? "MIDDLE" : "HIGH"]
10
+ )
11
+ end
@@ -0,0 +1,18 @@
1
+ # usage: ruby pa_course_code_cluster_pathway.rb
2
+ #
3
+ # courses with clusters/pathways by (deprecated) program areas
4
+ require 'csv'
5
+ require 'verso'
6
+
7
+ puts CSV.generate_line(%w{ Program\ Area Title Code Cluster Pathway })
8
+
9
+ Verso::ProgramAreaList.new.each do |pa|
10
+ pa.courses.each do |course|
11
+ course.occupation_data.each do |od|
12
+ puts CSV.generate_line(
13
+ [pa.title, course.title, course.code,
14
+ od.cluster.title, od.pathway.title]
15
+ )
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ # usage: ruby passing_score.rob
2
+ #
3
+ # list of credentials with passing score where available
4
+ require 'csv'
5
+ require 'verso'
6
+
7
+ puts CSV.generate_line(['Title', 'Source', 'Passing Score'])
8
+ Verso::CredentialList.new.each do |cred|
9
+ unless (cred.passing_score.to_s.empty? ||
10
+ cred.passing_score.to_s =~ /contact/i)
11
+ puts CSV.generate_line([cred.title, cred.source.title, cred.passing_score])
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ #usage: ruby related_courses.rb
2
+ #
3
+ # list of each course and the codes of its related courses
4
+ require 'csv'
5
+ require 'verso'
6
+
7
+ puts CSV.generate_line(%w{ Code Title Related\ Courses })
8
+
9
+ Verso::CourseList.new.each do |course|
10
+ puts CSV.generate_line(
11
+ [course.code, course.title,
12
+ course.related_courses.collect { |c| c.code }.join(' ')]
13
+ )
14
+ end
@@ -1,3 +1,3 @@
1
1
  module Verso
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
  s.add_runtime_dependency 'json'
21
- s.add_runtime_dependency 'addressable'
21
+ s.add_runtime_dependency 'addressable', '~> 2.3.5'
22
22
  s.add_development_dependency "webmock"
23
23
  s.add_development_dependency "redcarpet"
24
24
  s.add_development_dependency "rspec"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: verso
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Capps
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-06 00:00:00.000000000 Z
11
+ date: 2013-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: addressable
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 2.3.5
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 2.3.5
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: webmock
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -111,7 +111,8 @@ dependencies:
111
111
  description: A Ruby wrapper for the Virginia CTE Resource Center's Web API
112
112
  email:
113
113
  - himself@leecapps.com
114
- executables: []
114
+ executables:
115
+ - verso-mt
115
116
  extensions: []
116
117
  extra_rdoc_files: []
117
118
  files:
@@ -120,6 +121,21 @@ files:
120
121
  - LICENSE.md
121
122
  - README.md
122
123
  - Rakefile
124
+ - bin/verso-mt
125
+ - examples/associated_with.rb
126
+ - examples/ceop.rb
127
+ - examples/copyright_year.rb
128
+ - examples/course_notes.rb
129
+ - examples/cpo.rb
130
+ - examples/credential_cost.rb
131
+ - examples/credential_sources.rb
132
+ - examples/credentials.rb
133
+ - examples/hours.rb
134
+ - examples/hs_and_ms.rb
135
+ - examples/hs_v_ms.rb
136
+ - examples/pa_course_code_cluster_pathway.rb
137
+ - examples/passing_score.rb
138
+ - examples/related_courses.rb
123
139
  - lib/verso.rb
124
140
  - lib/verso/base.rb
125
141
  - lib/verso/cluster.rb
@@ -200,7 +216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
216
  version: '0'
201
217
  requirements: []
202
218
  rubyforge_project: verso
203
- rubygems_version: 2.0.0
219
+ rubygems_version: 2.0.3
204
220
  signing_key:
205
221
  specification_version: 4
206
222
  summary: Verso API wrapper