great_schools 0.1.0

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 (45) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +58 -0
  6. data/Rakefile +6 -0
  7. data/great_schools.gemspec +28 -0
  8. data/lib/great_schools.rb +88 -0
  9. data/lib/great_schools/census.rb +52 -0
  10. data/lib/great_schools/city.rb +72 -0
  11. data/lib/great_schools/district.rb +29 -0
  12. data/lib/great_schools/error.rb +51 -0
  13. data/lib/great_schools/ethnicity.rb +5 -0
  14. data/lib/great_schools/model.rb +45 -0
  15. data/lib/great_schools/rank.rb +5 -0
  16. data/lib/great_schools/result.rb +5 -0
  17. data/lib/great_schools/review.rb +47 -0
  18. data/lib/great_schools/school.rb +177 -0
  19. data/lib/great_schools/score.rb +47 -0
  20. data/lib/great_schools/test.rb +22 -0
  21. data/lib/great_schools/version.rb +14 -0
  22. data/spec/fixtures/browse_districts.xml +35 -0
  23. data/spec/fixtures/browse_schools.xml +46 -0
  24. data/spec/fixtures/city_overview.xml +12 -0
  25. data/spec/fixtures/error.xml +7 -0
  26. data/spec/fixtures/nearby_cities.xml +25 -0
  27. data/spec/fixtures/nearby_schools.xml +37 -0
  28. data/spec/fixtures/school_census_data.xml +40 -0
  29. data/spec/fixtures/school_profile.xml +70 -0
  30. data/spec/fixtures/school_reviews.xml +21 -0
  31. data/spec/fixtures/school_search.xml +38 -0
  32. data/spec/fixtures/school_test_scores.xml +33 -0
  33. data/spec/great_schools/census_spec.rb +28 -0
  34. data/spec/great_schools/city_spec.rb +72 -0
  35. data/spec/great_schools/district_spec.rb +34 -0
  36. data/spec/great_schools/ethnicity_spec.rb +17 -0
  37. data/spec/great_schools/rank_spec.rb +33 -0
  38. data/spec/great_schools/result_spec.rb +26 -0
  39. data/spec/great_schools/review_spec.rb +72 -0
  40. data/spec/great_schools/school_spec.rb +167 -0
  41. data/spec/great_schools/score_spec.rb +20 -0
  42. data/spec/great_schools/test_spec.rb +35 -0
  43. data/spec/great_schools_spec.rb +14 -0
  44. data/spec/spec_helper.rb +18 -0
  45. metadata +195 -0
@@ -0,0 +1,5 @@
1
+ module GreatSchools # :nodoc:
2
+ class Ethnicity < Model # :nodoc:
3
+ attr_accessor :name, :value, :year
4
+ end
5
+ end
@@ -0,0 +1,45 @@
1
+ require 'cgi'
2
+
3
+ module GreatSchools # :nodoc:
4
+ # = GreatSchools Base Model
5
+ class Model
6
+ class << self # Class methods
7
+ protected
8
+ # Makes a URL slug from the string.
9
+ #
10
+ # Replaces dashes with underscores, spaces with dashes, and URL encodes
11
+ # any special characters.
12
+ #
13
+ # ==== Examples
14
+ #
15
+ # parameterize('San Francisco') # => 'San-Francisco'
16
+ # parameterize('Cardiff-By-The-Sea') # => 'Cardiff_By_The_Sea'
17
+ def parameterize(string)
18
+ CGI.escape(string.gsub('-', '_').gsub(' ', '-'))
19
+ end
20
+ end
21
+
22
+ # Base initializer, map camelCased XML attributes from the GreatSchools API
23
+ # response to the appropriately underscored attribute setters.
24
+ def initialize(attributes = {})
25
+ attributes.each do |key, value|
26
+ key = underscore(key)
27
+ send("#{key}=", value) if respond_to?("#{key}=")
28
+ end
29
+ end
30
+
31
+ protected
32
+
33
+ # Makes an underscored, lowercase form from the expression in the string.
34
+ #
35
+ # ==== Examples
36
+ #
37
+ # underscore('myACRONYMString') # => 'my_acronym_string'
38
+ def underscore(word)
39
+ word = word.to_s.dup # unfreeze any frozen strings
40
+ word.gsub!(/([a-z])([A-Z])/,'\1_\2') # myACRONYMString => my_ACRONYMString
41
+ word.gsub!(/([A-Z]+)(?=[A-Z][a-z])/, '\1_\2') # my_ACRONYMString => my_ACRONYM_String
42
+ word.downcase # my_ACRONYM_String => my_acronym_string
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ module GreatSchools # :nodoc:
2
+ class Rank < Model # :nodoc:
3
+ attr_accessor :name, :scale, :year, :description, :score
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module GreatSchools # :nodoc:
2
+ class Result < Model # :nodoc:
3
+ attr_accessor :grade_name, :score, :subject_name, :test_id, :year
4
+ end
5
+ end
@@ -0,0 +1,47 @@
1
+ module GreatSchools # :nodoc:
2
+ # = GreatSchools Review
3
+ class Review < Model
4
+ attr_accessor :school_name, :school_address
5
+ attr_accessor :review_link, :rating, :submitter, :posted_date, :comments
6
+
7
+ class << self # Class methods
8
+ # Returns a list of the most recent reviews for any schools in a city.
9
+ #
10
+ # ==== Attributes
11
+ #
12
+ # * +state+ - Two letter state abbreviation
13
+ # * +city+ - Name of city
14
+ #
15
+ # ==== Options
16
+ #
17
+ # * +:cutoff_age+ - Reviews must have been published after this many days
18
+ # ago to be returned.
19
+ # * +:limit+ - Maximum number of reviews to return. This defaults to 5.
20
+ def for_city(state, city, options = {})
21
+ options[:cutoffAge] = options.delete(:cutoff_age) # TODO: make helper method to camelCase or map query attributes
22
+
23
+ response = GreatSchools::API.get("reviews/city/#{state.upcase}/#{parameterize(city)}", options.slice(:cutoffAge, :limit))
24
+
25
+ Array.wrap(response).map { |review| new(review) }
26
+ end
27
+
28
+ # Returns a list of the most recent reviews for a school.
29
+ #
30
+ # ==== Attributes
31
+ #
32
+ # * +state+ - Two letter state abbreviation
33
+ # * +id+ - Numeric id of a school. This GreatSchools ID is included in
34
+ # other listing requests like +GreatSchools::School#browse+
35
+ # and +GreatSchools::School#nearby+
36
+ #
37
+ # ==== Options
38
+ #
39
+ # * +:limit+ - Maximum number of reviews to return. This defaults to 5.
40
+ def for_school(state, id, options = {})
41
+ response = GreatSchools::API.get("reviews/school/#{state.upcase}/#{id}", options.slice(:limit))
42
+
43
+ Array.wrap(response).map { |review| new(review) }
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,177 @@
1
+ module GreatSchools # :nodoc:
2
+ # = GreatSchools School
3
+ class School < Model
4
+ attr_accessor :id, :name, :type, :grade_range, :enrollment, :district_id, :district, :district_nces_id, :nces_id
5
+ attr_accessor :city, :state, :address, :phone, :fax, :website, :latitude, :longitude
6
+ attr_accessor :overview_link, :ratings_link, :reviews_link, :parent_reviews, :parent_rating
7
+
8
+ alias_method :gs_id=, :id=
9
+ alias_method :lat=, :latitude=
10
+ alias_method :lon=, :longitude=
11
+
12
+ class << self # Class methods
13
+ # Returns a list of schools in a city.
14
+ #
15
+ # ==== Attributes
16
+ #
17
+ # * +state+ - Two letter state abbreviation
18
+ # * +city+ - Name of city
19
+ #
20
+ # ==== Options
21
+ #
22
+ # * +:school_types+ - Type of school(s) you wish to appear in the list:
23
+ # 'public', 'charter', and/or 'private'
24
+ # * +:level+ - Level of school you wish to appear in the list:
25
+ # 'elementary-schools', 'middle-schools', or 'high-schools'
26
+ # * +:sort+ - How to sort the results, either by name (ascending),
27
+ # by GreatSchools rating (descending), or by overall
28
+ # parent rating (descending). The default sort is name
29
+ # (ascending). When sorted by rating, schools without
30
+ # a rating will appear last. Options: 'name',
31
+ # 'gs_rating', or 'parent_rating'
32
+ # * +:limit+ - Maximum number of schools to return. This defaults
33
+ # to 200. To get all results, use -1.
34
+ # --
35
+ # TODO: handle validations
36
+ # ++
37
+ def browse(state, city, options = {})
38
+ school_types = Array.wrap(options.delete(:school_types)).join('-')
39
+ level = options.delete(:level)
40
+
41
+ url = "schools/#{state.upcase}/#{parameterize(city)}"
42
+ url << "/#{school_types}" if school_types.present?
43
+ url << "/#{level}" if level.present?
44
+
45
+ response = GreatSchools::API.get(url, options.slice(:sort, :limit))
46
+
47
+ Array.wrap(response).map { |school| new(school) }
48
+ end
49
+
50
+ # Returns a list of schools closest to the center of a city, ZIP Code or
51
+ # address.
52
+ #
53
+ # ==== Attributes
54
+ #
55
+ # * +state+ - Two letter state abbreviation
56
+ #
57
+ # ==== Options
58
+ #
59
+ # * +:zip_code+ - 5 digit zip code
60
+ # * +:city+ - Name of city
61
+ # * +:address+ - Address of location
62
+ # * +:latitude+ - Latitude of location
63
+ # * +:longitude+ - Longitude of location
64
+ # * +:school_types+ - Type of school(s) you wish to appear in the list:
65
+ # 'public', 'charter', and/or 'private'
66
+ # * +:level+ - Level of school you wish to appear in the list:
67
+ # 'elementary-schools', 'middle-schools', or 'high-schools'
68
+ # * +:minimum_schools+ - Minimum number of schools to return. When provided,
69
+ # if the initial query field yields fewer schools than
70
+ # this value, the radius will be increased in 5 mile
71
+ # increments to a maximum of 50 miles or until the
72
+ # result set has enough schools to meet this value.
73
+ # Maximum value is 200. This value must be less than
74
+ # the limit or else it is ignored.
75
+ # * +:radius+ - Miles radius to confine search to. This default to 5,
76
+ # with a maximum of 50.
77
+ # * +:limit+ - Maximum number of schools to return. This defaults to 200.
78
+ # --
79
+ # TODO: handle validations
80
+ # ++
81
+ def nearby(state, options = {})
82
+ options[:lat] = options.delete(:latitude)
83
+ options[:levelCode] = options.delete(:level)
84
+ options[:lon] = options.delete(:longitude)
85
+ options[:minimumSchools] = options.delete(:minimum_schools)
86
+ options[:schoolType] = options.delete(:school_types).try(:join, '-')
87
+ options[:state] = state
88
+ options[:zip] = options.delete(:zip_code)
89
+
90
+ options.slice!(:address, :city, :lat, :levelCode, :limit, :lon, :minimumSchools, :radius, :schoolType, :state, :zip)
91
+
92
+ response = GreatSchools::API.get('schools/nearby', options)
93
+
94
+ Array.wrap(response).map { |school| new(school) }
95
+ end
96
+
97
+ # Returns profile data for a specific school.
98
+ #
99
+ # ==== Attributes
100
+ #
101
+ # * +state+ - Two letter state abbreviation
102
+ # * +id+ - Numeric id of a school. This GreatSchools ID is included in
103
+ # other listing requests like +GreatSchools::School#browse+
104
+ # and +GreatSchools::School#nearby+
105
+ def profile(state, id)
106
+ response = GreatSchools::API.get("schools/#{state.upcase}/#{id}")
107
+
108
+ new(response)
109
+ end
110
+
111
+ # Returns a list of schools based on a search string.
112
+ #
113
+ # ==== Attributes
114
+ #
115
+ # * +state+ - Two letter state abbreviation
116
+ # * +query+ - Search query string
117
+ #
118
+ # ==== Options
119
+ #
120
+ # * +:level+ - Level of school you wish to appear in the list:
121
+ # 'elementary-schools', 'middle-schools', or 'high-schools'
122
+ # * +:sort+ - This call by default sorts the results by relevance. You
123
+ # can sort the results alphabetically by using 'alpha'.
124
+ # * +:limit+ - Maximum number of schools to return. This defaults to
125
+ # 200 and must be at least 1.
126
+ # --
127
+ # TODO: handle validations
128
+ # ++
129
+ def search(state, query, options = {})
130
+ options[:levelCode] = options.delete(:level)
131
+ options[:q] = query
132
+ options[:state] = state
133
+ options.slice!(:state, :q, :levelCode, :sort, :limit)
134
+
135
+ response = GreatSchools::API.get('search/schools', options)
136
+
137
+ Array.wrap(response).map { |school| new(school) }
138
+ end
139
+ end
140
+
141
+ # Returns census and profile data for the school.
142
+ def census
143
+ GreatSchools::Census.for_school(state, id)
144
+ end
145
+
146
+ # Set an array of +GreatSchools::Review+.
147
+ #
148
+ # ==== Attributes
149
+ #
150
+ # * +params+ - a +Hash+ or +Array+ of +GreatSchools::Review+ attributes.
151
+ def parent_reviews=(params)
152
+ @parent_reviews = []
153
+
154
+ params = params['review'] if params.is_a?(Hash) && params.key?('review')
155
+
156
+ Array.wrap(params).each do |hash|
157
+ @parent_reviews << GreatSchools::Review.new(hash)
158
+ end
159
+
160
+ @parent_reviews
161
+ end
162
+
163
+ # Returns a list of the most recent reviews for the school.
164
+ #
165
+ # ==== Options
166
+ #
167
+ # * +:limit+ - Maximum number of reviews to return. This defaults to 5.
168
+ def reviews(options = {})
169
+ GreatSchools::Review.for_school(state, id, options.slice(:limit))
170
+ end
171
+
172
+ # Returns test and rank data for the school.
173
+ def score
174
+ GreatSchools::Score.for_school(state, id)
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,47 @@
1
+ module GreatSchools # :nodoc:
2
+ # = GreatSchools Score
3
+ class Score < Model
4
+ attr_accessor :school_name, :rank, :tests
5
+
6
+ class << self # Class methods
7
+ # Returns test and rank data for a specific school.
8
+ #
9
+ # ==== Attributes
10
+ #
11
+ # * +state+ - Two letter state abbreviation
12
+ # * +id+ - Numeric id of a school. This GreatSchools ID is included in
13
+ # other listing requests like +GreatSchools::School#browse+
14
+ # and +GreatSchools::School#nearby+
15
+ def for_school(state, id)
16
+ response = GreatSchools::API.get("school/tests/#{state.upcase}/#{id}")
17
+
18
+ new(response)
19
+ end
20
+ end
21
+
22
+ # Set the +GreatSchools::Rank+.
23
+ #
24
+ # ==== Attributes
25
+ #
26
+ # * +params+ - a +Hash+ of +GreatSchools::Rank+ attributes.
27
+ def rank=(params)
28
+ @rank = GreatSchools::Rank.new(params)
29
+ end
30
+
31
+ # Set an array of +GreatSchools::Test+.
32
+ #
33
+ # ==== Attributes
34
+ #
35
+ # * +params+ - a +Hash+ or +Array+ of +GreatSchools::Test+ attributes.
36
+ def tests=(params)
37
+ @tests = []
38
+
39
+ Array.wrap(params).each do |hash|
40
+ @tests << GreatSchools::Test.new(hash)
41
+ end
42
+
43
+ @tests
44
+ end
45
+ alias_method :test=, :tests=
46
+ end
47
+ end
@@ -0,0 +1,22 @@
1
+ module GreatSchools # :nodoc:
2
+ # = GreatSchools Test
3
+ class Test < Model
4
+ attr_accessor :name, :id, :description, :abbreviation, :scale, :level_code, :results
5
+
6
+ # Set an array of +GreatSchools::Result+.
7
+ #
8
+ # ==== Attributes
9
+ #
10
+ # * +params+ - a +Hash+ or +Array+ of +GreatSchools::Result+ attributes.
11
+ def results=(params)
12
+ @results = []
13
+
14
+ Array.wrap(params).each do |hash|
15
+ @results << GreatSchools::Result.new(hash)
16
+ end
17
+
18
+ @results
19
+ end
20
+ alias_method :test_result=, :results=
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ module GreatSchools # :nodoc:
2
+ class Version # :nodoc:
3
+ MAJOR = 0 # version when you make incompatible API changes
4
+ MINOR = 1 # version when you add functionality in a backwards-compatible manner
5
+ PATCH = 0 # version when you make backwards-compatible bug fixes
6
+
7
+ class << self # Class methods
8
+ # MAJOR.MINOR.PATCH per Semantic Versioning 2.0.0
9
+ def to_s
10
+ "#{MAJOR}.#{MINOR}.#{PATCH}"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+ <districts>
3
+ <district>
4
+ <name>San Francisco Unified School District</name>
5
+ <ncesCode>0634410</ncesCode>
6
+ <districtRating>6</districtRating>
7
+ <address>555 Franklin St., San Francisco, CA 94102</address>
8
+ <phone>(415) 241-6000</phone>
9
+ <fax>(415) 241-6012</fax>
10
+ <website>http://www.sfusd.k12.ca.us</website>
11
+ <gradeRange>K-12 &amp; ungraded</gradeRange>
12
+ <totalSchools>121</totalSchools>
13
+ <elementarySchools>84</elementarySchools>
14
+ <middleSchools>36</middleSchools>
15
+ <highSchools>34</highSchools>
16
+ <publicSchools>113</publicSchools>
17
+ <charterSchools>8</charterSchools>
18
+ </district>
19
+ <district>
20
+ <name>San Francisco County Office of Education</name>
21
+ <ncesCode>0691111</ncesCode>
22
+ <districtRating>1</districtRating>
23
+ <address>555 Franklin St., San Francisco, CA 94102</address>
24
+ <phone>(415) 241-6000</phone>
25
+ <fax>(415) 241-6012</fax>
26
+ <website>http://www.sfusd.k12.ca.us</website>
27
+ <gradeRange>K-12</gradeRange>
28
+ <totalSchools>4</totalSchools>
29
+ <elementarySchools>2</elementarySchools>
30
+ <middleSchools>3</middleSchools>
31
+ <highSchools>4</highSchools>
32
+ <publicSchools>4</publicSchools>
33
+ <charterSchools>0</charterSchools>
34
+ </district>
35
+ </districts>
@@ -0,0 +1,46 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+ <schools>
3
+ <school>
4
+ <gsId>13978</gsId>
5
+ <name>Alder Creek Middle School</name>
6
+ <type>public</type>
7
+ <gradeRange>6-8</gradeRange>
8
+ <enrollment>598</enrollment>
9
+ <city>Truckee</city>
10
+ <state>CA</state>
11
+ <districtId>509</districtId>
12
+ <district>Tahoe-Truckee Joint Unified School District</district>
13
+ <districtNCESId>0638770</districtNCESId>
14
+ <address>10931 Alder Dr., Truckee, CA 96161</address>
15
+ <phone>(530) 582-2750</phone>
16
+ <fax>(530) 582-7640</fax>
17
+ <website>http://www.ttusd.org</website>
18
+ <ncesId>063877011005</ncesId>
19
+ <lat>39.3454</lat>
20
+ <lon>-120.1735</lon>
21
+ <overviewLink>http://www.greatschools.org/modperl/browse_school/ca/13978?s_cid=gsapi</overviewLink>
22
+ <ratingsLink>http://www.greatschools.org/school/rating.page?state=CA&amp;id=13978&amp;s_cid=gsapi</ratingsLink>
23
+ <reviewsLink>http://www.greatschools.org/school/parentReviews.page?state=CA&amp;id=13978&amp;s_cid=gsapi</reviewsLink>
24
+ </school>
25
+ <school>
26
+ <gsId>11039</gsId>
27
+ <name>Cold Stream Alternative School</name>
28
+ <type>public</type>
29
+ <gradeRange>9-12</gradeRange>
30
+ <enrollment>47</enrollment>
31
+ <city>Truckee</city>
32
+ <state>CA</state>
33
+ <districtId>509</districtId>
34
+ <district>Tahoe-Truckee Joint Unified School District</district>
35
+ <districtNCESId>0638770</districtNCESId>
36
+ <address>11661 Donner Pass Rd., Truckee, CA 96161</address>
37
+ <phone>(530) 582-2640</phone>
38
+ <fax>(530) 582-7640</fax>
39
+ <ncesId>063877006175</ncesId>
40
+ <lat>39.3259</lat>
41
+ <lon>-120.2147</lon>
42
+ <overviewLink>http://www.greatschools.org/modperl/browse_school/ca/11039?s_cid=gsapi</overviewLink>
43
+ <ratingsLink>http://www.greatschools.org/school/rating.page?state=CA&amp;id=11039&amp;s_cid=gsapi</ratingsLink>
44
+ <reviewsLink>http://www.greatschools.org/school/parentReviews.page?state=CA&amp;id=11039&amp;s_cid=gsapi</reviewsLink>
45
+ </school>
46
+ </schools>