great_schools 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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>