freeb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +327 -0
  3. data/Rakefile +38 -0
  4. data/app/models/freebase_model_relation.rb +6 -0
  5. data/app/models/freebase_topic.rb +9 -0
  6. data/app/models/freebase_topic_relation.rb +6 -0
  7. data/db/migrate/20121226072811_create_freebase_topics.rb +12 -0
  8. data/db/migrate/20121226073507_create_freebase_topic_relations.rb +15 -0
  9. data/db/migrate/20121226185919_create_freebase_model_relations.rb +15 -0
  10. data/lib/freeb.rb +28 -0
  11. data/lib/freeb/api.rb +91 -0
  12. data/lib/freeb/config.rb +25 -0
  13. data/lib/freeb/converter.rb +60 -0
  14. data/lib/freeb/dsl.rb +25 -0
  15. data/lib/freeb/engine.rb +5 -0
  16. data/lib/freeb/exceptions.rb +3 -0
  17. data/lib/freeb/model_config.rb +172 -0
  18. data/lib/freeb/models.rb +175 -0
  19. data/lib/freeb/topic.rb +57 -0
  20. data/lib/freeb/version.rb +3 -0
  21. data/lib/generators/freeb/migration_generator.rb +24 -0
  22. data/lib/generators/freeb/templates/migration.rb +13 -0
  23. data/test/dummy/README.rdoc +261 -0
  24. data/test/dummy/Rakefile +7 -0
  25. data/test/dummy/app/assets/javascripts/application.js +15 -0
  26. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  27. data/test/dummy/app/controllers/application_controller.rb +3 -0
  28. data/test/dummy/app/helpers/application_helper.rb +2 -0
  29. data/test/dummy/app/models/music_artist.rb +7 -0
  30. data/test/dummy/app/models/us_state.rb +6 -0
  31. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  32. data/test/dummy/config.ru +4 -0
  33. data/test/dummy/config/application.rb +59 -0
  34. data/test/dummy/config/boot.rb +10 -0
  35. data/test/dummy/config/database.yml +25 -0
  36. data/test/dummy/config/environment.rb +5 -0
  37. data/test/dummy/config/environments/development.rb +37 -0
  38. data/test/dummy/config/environments/production.rb +67 -0
  39. data/test/dummy/config/environments/test.rb +37 -0
  40. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  41. data/test/dummy/config/initializers/freeb.rb +3 -0
  42. data/test/dummy/config/initializers/inflections.rb +15 -0
  43. data/test/dummy/config/initializers/mime_types.rb +5 -0
  44. data/test/dummy/config/initializers/secret_token.rb +7 -0
  45. data/test/dummy/config/initializers/session_store.rb +8 -0
  46. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  47. data/test/dummy/config/locales/en.yml +5 -0
  48. data/test/dummy/config/routes.rb +58 -0
  49. data/test/dummy/db/migrate/20121227043946_create_freebase_topics.freeb.rb +13 -0
  50. data/test/dummy/db/migrate/20121227043947_create_freebase_topic_relations.freeb.rb +16 -0
  51. data/test/dummy/db/migrate/20121227043948_create_freebase_model_relations.freeb.rb +16 -0
  52. data/test/dummy/db/migrate/20121227044336_create_music_artists.rb +15 -0
  53. data/test/dummy/db/migrate/20121227170033_create_us_states.rb +13 -0
  54. data/test/dummy/db/schema.rb +71 -0
  55. data/test/dummy/public/404.html +26 -0
  56. data/test/dummy/public/422.html +26 -0
  57. data/test/dummy/public/500.html +25 -0
  58. data/test/dummy/public/favicon.ico +0 -0
  59. data/test/dummy/script/rails +6 -0
  60. data/test/dummy/spec/freeb_spec.rb +32 -0
  61. data/test/dummy/spec/music_artist_spec.rb +58 -0
  62. data/test/dummy/spec/spec_helper.rb +38 -0
  63. data/test/dummy/spec/us_state_spec.rb +11 -0
  64. data/test/freeb_test.rb +7 -0
  65. data/test/test_helper.rb +15 -0
  66. metadata +217 -0
@@ -0,0 +1,20 @@
1
+ Copyright 2012 Tom Benner
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,327 @@
1
+ Freeb
2
+ =====
3
+ Store the world's knowledge in Rails models
4
+
5
+ Description
6
+ -----------
7
+
8
+ Freeb lets you easily create Rails models for just about any publicly available content type (e.g. Person, Film, etc) and populate them automagically with comprehensive data from [Freebase](http://www.freebase.com/). For example, a Person model would store data like [this](http://www.freebase.com/view/people/person).
9
+
10
+ Freebase has an enormous wealth of structured data for thousands of content types, each with their own specific, comprehensive schema (e.g. film's [schema](http://www.freebase.com/schema/film/film) and [records](http://www.freebase.com/view/film/film)). It's gigantic, with a scope and scale that are much larger and more comprehensive than Wikipedia's (see Available Data below).
11
+
12
+ For example, if you wanted to have bands and their albums and genres in your app, you would simply create a MusicArtist model that has type [/music/artist](http://www.freebase.com/schema/music/artist) and specify what associated data should be included (e.g. description, genres, albums, etc). When you call `MusicArtist.fcreate_by_name('The Beatles')`, data about The Beatles will be automagically pulled from Freebase and stored in a `music_artists` table that has bespoke columns.
13
+
14
+ Freeb lets you:
15
+
16
+ * Easily access and store just about every type of publicly available content (e.g. people, music, movies, sports teams, types of beer, etc). Freebase is like Wikipedia in database form, but with even more content.
17
+ * Quickly add a great deal of content and detail to your app
18
+ * Give your app a much wider and thorough variety of content types
19
+
20
+ Available Data
21
+ --------------
22
+
23
+ Freebase has thousands of content types, each with their own specific, comprehensive schema (e.g. [film's schema](http://www.freebase.com/schema/film/film)). The types range from very broad to very specific. Here are just a few of the types:
24
+
25
+ * [People](http://www.freebase.com/view/people/person)
26
+ * [Films](http://www.freebase.com/view/film/film)
27
+ * [Albums](http://www.freebase.com/view/music/album)
28
+ * [Consumer products](http://www.freebase.com/view/business/consumer_product)
29
+ * [Mass transit stops](http://www.freebase.com/view/metropolitan_transit/transit_stop)
30
+ * [Types of cheese](http://www.freebase.com/view/food/cheese)
31
+ * [Golf course architects](http://www.freebase.com/view/sports/golf_course_designer)
32
+
33
+ You can browse thousands of other types in the [Freebase schema](http://www.freebase.com/schema). This page shows domains, which each contain many types. Click on a type to see its schema.
34
+
35
+ Installation
36
+ ------------
37
+
38
+ Add freeb to your Gemfile:
39
+
40
+ gem 'freeb', :git => 'git://github.com/tombenner/freeb.git'
41
+
42
+ Install and run the migrations:
43
+
44
+ rake freeb:install:migrations
45
+ rake db:migrate
46
+
47
+ Creating Models
48
+ ---------------
49
+
50
+ Create a model (without a migration) and specify its type and the information that will be stored with it:
51
+
52
+ class MusicArtist < ActiveRecord::Base
53
+ freeb do
54
+ type "/music/artist"
55
+ properties "description", "active_start", "active_end"
56
+ topics :genres => "genre"
57
+ end
58
+ end
59
+
60
+ `properties` specifies columns that will be in the MusicArtist table (in addition to id, freebase_id, and name), and `topics` are stored as FreebaseTopics (simple records with basically just a name and an ID). Please see Model Configuration below for details.
61
+
62
+ Create the model's table:
63
+
64
+ rails g freeb:migration MusicArtist
65
+ rake db:migrate
66
+
67
+ You can now easily create MusicArtists, which will automatically retrieve and store all of the data specified in the model:
68
+
69
+ artist = MusicArtist.fcreate_by_name('The Beatles')
70
+ # <MusicArtist id: 1, freebase_id: "/en/the_beatles", name: "The Beatles", description: "The Beatles were an English rock band formed in Liv...", ...>
71
+
72
+ artist.genres
73
+ # [#<FreebaseTopic id: 1, freebase_id: "/en/rock_music", name: "Rock music", ...>, <FreebaseTopic id: 2, freebase_id: "/en/pop_music", name: "Pop music", ...>, ...]
74
+
75
+ To make associations between two Freeb models (e.g. MusicArtist has\_many Albums), use has_many:
76
+
77
+ class MusicArtist < ActiveRecord::Base
78
+ freeb do
79
+ type "/music/artist"
80
+ properties "description", "active_start", "active_end"
81
+ topics :genres => "genre"
82
+ has_many :albums => "album"
83
+ end
84
+ end
85
+
86
+ class Album < ActiveRecord::Base
87
+ freeb do
88
+ type "/music/album"
89
+ properties "release_date"
90
+ topics :genres => "genre"
91
+ end
92
+ end
93
+
94
+ When you create a MusicArtist, its albums and genres will be created automatically:
95
+
96
+ artist = MusicArtist.fcreate_by_name('The Beatles')
97
+ # <MusicArtist id: 1, freebase_id: "/en/the_beatles", name: "The Beatles", description: "The Beatles were an English rock band formed in Liv...", ...>
98
+
99
+ artist.albums.first
100
+ # <Album id: 1, freebase_id: "/en/introducing_the_beatles", name: "Introducing...The Beatles", release_date: "1963-07-22 00:00:00", ...>
101
+
102
+ artist.albums.first.genres
103
+ # <FreebaseTopic id: 1, freebase_id: "/en/rock_music", name: "Rock music", ...>, #<FreebaseTopic id: 4, freebase_id: "/wikipedia/de_id/3375255", name: "Rock and roll", ...>
104
+
105
+ Model Configuration
106
+ -------------------
107
+
108
+ Model configuration consists of setting the `type` and setting the data that will be stored (`properties`, `topics`, `has_many`).
109
+
110
+ #### type
111
+
112
+ The Freebase type that the model corresponds to. [Here's](http://www.freebase.com/schema) a list of domains, which each contain many of types.
113
+
114
+ #### properties
115
+
116
+ A list of properties that will be stored in the model. You can see the available properties by clicking on a type in Freebase (see `type` above). For example, the list of properties for the type `/people/person` is [here](http://www.freebase.com/schema/people/person). To store Date of Birth in a Person model, you would write:
117
+
118
+ properties "date_of_birth"
119
+
120
+ The type is inferred (`date_of_birth` is translated to `/people/person/date_of_birth`), but you can also specify the entire ID:
121
+
122
+ properties "/people/person/date_of_birth"
123
+
124
+ Properties can then be accessed and used in queries like any other column:
125
+
126
+ Person.first.date_of_birth
127
+ Person.order('date_of_birth DESC')
128
+
129
+ #### topics
130
+
131
+ If a Freebase type has associated topics, you can store these either as simple records using `topics` or in a new dedicated model with `has_many` (see below).
132
+
133
+ The hash key is the name of the method through which they'll be accessed, and the hash value is the last part of the property ID (or the full ID; see `properties`).
134
+
135
+ For example, to store a [music artist](http://www.freebase.com/schema/music/artist)'s genres (/music/artist/genre), use:
136
+
137
+ topics :genres => "genre"
138
+
139
+ You can then access those genres like any other association:
140
+
141
+ MusicArtist.first.genres
142
+ genre = MusicArtist.first.genres.first
143
+ genre.music_artists
144
+
145
+ #### has_many
146
+
147
+ If you want to create associations between two Freeb models, use `has_many`. The hash key is the method through which the records will be accessed, and the hash value is the last part of the property ID (or the full ID; see `properties`). For example, if MusicArtist has_many Albums:
148
+
149
+ class MusicArtist < ActiveRecord::Base
150
+ freeb do
151
+ type "/music/artist"
152
+ properties "description", "active_start", "active_end"
153
+ topics :genres => "genre"
154
+ has_many :albums => "album"
155
+ end
156
+ end
157
+
158
+ class Album < ActiveRecord::Base
159
+ freeb do
160
+ type "/music/album"
161
+ properties "release_date"
162
+ topics :genres => "genre"
163
+ end
164
+ end
165
+
166
+ Model Methods
167
+ -------------
168
+
169
+ In general, Freeb methods behave similarly to ActiveModel's CRUD methods, but are prefixed with an "f" and deal with creating and updating local objects with data from Freebase.
170
+
171
+ ### Class Methods
172
+
173
+ #### fcreate(freebase_id)
174
+
175
+ Creates a new record using a Freebase ID:
176
+
177
+ MusicArtist.fcreate('/en/the_beatles')
178
+ # <MusicArtist id: 1, freebase_id: "/en/the_beatles", name: "The Beatles", description: "The Beatles were an English rock band formed in Liv...", ...>
179
+
180
+ You can also pass an array of Freebase IDs:
181
+
182
+ MusicArtist.fcreate(['/en/the_beatles', '/en/the_beach_boys'])
183
+
184
+ Or use MQL to create all entities that match specific conditions:
185
+
186
+ # Only create states with an area larger than 500,000 sq km
187
+ UsState.fcreate([{"/location/location/area>" => 500000}])
188
+
189
+ #### fcreate\_by\_name(name)
190
+
191
+ Creates a new record using a name:
192
+
193
+ MusicArtist.fcreate_by_name('The Beatles')
194
+ # <MusicArtist id: 1, freebase_id: "/en/the_beatles", name: "The Beatles", description: "The Beatles were an English rock band formed in Liv...", ...>
195
+
196
+ Or an array of names:
197
+
198
+ MusicArtist.fcreate_by_name(['The Beatles', 'The Beach Boys'])
199
+
200
+ #### fcreate_all
201
+
202
+ Creates records for every Freebase entity of the model's type:
203
+
204
+ states = UsState.fcreate_all
205
+ states.count
206
+ # 50
207
+
208
+ *Note that many types have huge numbers of entities in Freebase; if you want to create only a subset of those entities, you can use `fcreate(mql)` and specify filters in MQL (see `fcreate`).*
209
+
210
+ #### fnew(freebase_id)
211
+
212
+ Same as fcreate, but doesn't save the record.
213
+
214
+ #### fnew\_by\_name(name)
215
+
216
+ Same as fcreate\_by\_name, but doesn't save the record.
217
+
218
+ ### Instance Methods
219
+
220
+ #### fupdate
221
+
222
+ Updates the record's Freebase data:
223
+
224
+ MusicArtist.first.fupdate
225
+
226
+ #### fimage
227
+
228
+ Returns the Freebase image URL for the record:
229
+
230
+ MusicArtist.first.fimage
231
+ # "https://usercontent.googleapis.com/freebase/v1/image/en/the_beatles"
232
+
233
+ Freebase's image service also provides great options that let you specify the image's dimensions and other attributes. Every parameter that [their service](http://wiki.freebase.com/wiki/Image_Service) supports is supported:
234
+
235
+ MusicArtist.first.fimage(:maxwidth => 200, :maxheight => 200)
236
+ # "https://usercontent.googleapis.com/freebase/v1/image/en/the_beatles?maxheight=200&maxwidth=200"
237
+
238
+ API
239
+ ---
240
+
241
+ Freeb also includes a wrapper for the Freebase API that uses smart objects. Properties can be retrieved from them using methods.
242
+
243
+ beatles = Freeb.get('/en/the_beatles')
244
+
245
+ beatles.description
246
+ # "The Beatles were an English rock band formed in Liv..."
247
+
248
+ beatles['/music/artist/active_start']
249
+ # "1957"
250
+
251
+ #### Freeb.get(freebase_id)
252
+
253
+ Returns a topic object for the specified Freebase ID.
254
+
255
+ Freeb.get('/en/the_beatles')
256
+ # <Freeb::Topic:0x007fd9fbf6f978 @raw_data={"id"=>"/en/the_beatles", "name"=>"The Beatles"}>
257
+
258
+ #### Freeb.search(params)
259
+
260
+ Returns an array of topic objects for a Freebase search. The available parameters are listed [here](http://wiki.freebase.com/wiki/ApiSearch).
261
+
262
+ Freeb.search(:keyword => 'The Beatles')
263
+ # [#<Freeb::Topic:0x007fd6f22d4698 "id"=>"/en/the_beatles", "name"=>"The Beatles", "notable"=>{"name"=>"Musical Group", "id"=>"/music/musical_group"}, "lang"=>"en", "score"=>933.343811}>, #<Freeb::Topic:0x007fd6f22d4620 @raw_data={"mid"=>"/m/03j24kf", "id"=>"/en/paul_mccartney", "name"=>"Paul McCartney", "notable"=>{"name"=>"Musician", "id"=>"/m/09jwl"}, "lang"=>"en", "score"=>384.929718}>, #<Freeb::Topic:0x007fd6f22d45a8 @raw_data={"mid"=>"/m/01vsl3_", "id"=>"/en/john_lennon", "name"=>"John Lennon",
264
+
265
+ #### Freeb.topic(mql)
266
+
267
+ Returns a topic object for the specified MQL. This is useful if you want to grab a number of properties using a single API call.
268
+
269
+ mql = {
270
+ :id => '/en/the_beatles',
271
+ :name => nil,
272
+ :'/music/artist/genre' => [{:id => nil, :name => nil}]
273
+ }
274
+ beatles = Freeb.topic(mql)
275
+
276
+ beatles.name
277
+ "The Beatles"
278
+
279
+ beatles['/music/artist/genre']
280
+ # [{"name"=>"Rock music", "id"=>"/en/rock_music"}, {"name"=>"Pop music", "id"=>"/en/pop_music"}, ...]
281
+
282
+ You can also use an array as an argument to get an array of topics:
283
+
284
+ mql = [{
285
+ :type => "/location/us_state",
286
+ :id => nil,
287
+ :name => nil
288
+ }]
289
+ Freeb.topic(mql)
290
+ # [#<Freeb::Topic:0x007fe5ebe491d8 @raw_data={"type"=>"/location/us_state", "id"=>"/en/alabama", "name"=>"Alabama"}>, #<Freeb::Topic:0x007fe5ebe49160 @raw_data={"type"=>"/location/us_state", "id"=>"/en/alaska", "name"=>"Alaska"}>, ...]
291
+
292
+ #### Freeb.mqlread(mql)
293
+
294
+ Same as Freeb.topic, but returns the response's hash instead of a Freeb:Topic.
295
+
296
+ Configuration
297
+ -------------
298
+
299
+ You can modify Freeb's default settings by adding an initializer:
300
+
301
+
302
+ # config/initializers/freeb.rb
303
+ Freeb.config do |config|
304
+ config.api_key "my_api_key"
305
+ config.cache :expires_in => 7.days
306
+ end
307
+
308
+ #### api_key
309
+
310
+ Freeb doesn't use an [API key](http://wiki.freebase.com/wiki/Freebase_API#API_Keys) by default, but you can add one to use it in all API requests:
311
+
312
+ config.api_key "my_api_key"
313
+
314
+ #### cache
315
+
316
+ Freeb caches Freebase API responses by default, using `:expires_in => 1.day`. You can change this duration:
317
+
318
+ config.cache :expires_in => 7.days
319
+
320
+ Or disable the caching entirely:
321
+
322
+ config.cache :is_active => false
323
+
324
+ License
325
+ -------
326
+
327
+ Freeb is released under the MIT License. Please see the MIT-LICENSE file for details.
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Freeb'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
28
+ require 'rake/testtask'
29
+
30
+ Rake::TestTask.new(:test) do |t|
31
+ t.libs << 'lib'
32
+ t.libs << 'test'
33
+ t.pattern = 'test/**/*_test.rb'
34
+ t.verbose = false
35
+ end
36
+
37
+
38
+ task :default => :test
@@ -0,0 +1,6 @@
1
+ class FreebaseModelRelation < ActiveRecord::Base
2
+ attr_accessible :object_id, :object_type, :property, :subject_id, :subject_type
3
+
4
+ belongs_to :object, :polymorphic => true
5
+ belongs_to :subject, :polymorphic => true
6
+ end
@@ -0,0 +1,9 @@
1
+ class FreebaseTopic < ActiveRecord::Base
2
+ attr_accessible :freebase_id, :name
3
+
4
+ has_many :freebase_topic_relations
5
+
6
+ def to_s
7
+ name
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ class FreebaseTopicRelation < ActiveRecord::Base
2
+ attr_accessible :freebase_topic_id, :property, :subject_id, :subject_type
3
+
4
+ belongs_to :freebase_topic
5
+ belongs_to :subject, :polymorphic => true
6
+ end
@@ -0,0 +1,12 @@
1
+ class CreateFreebaseTopics < ActiveRecord::Migration
2
+ def change
3
+ create_table :freebase_topics do |t|
4
+ t.string :freebase_id
5
+ t.string :name
6
+
7
+ t.timestamps
8
+ end
9
+
10
+ add_index :freebase_topics, :freebase_id
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ class CreateFreebaseTopicRelations < ActiveRecord::Migration
2
+ def change
3
+ create_table :freebase_topic_relations do |t|
4
+ t.string :subject_type
5
+ t.integer :subject_id
6
+ t.string :property
7
+ t.integer :freebase_topic_id
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :freebase_topic_relations, [:subject_type, :subject_id, :property], :name => "subject_property"
13
+ add_index :freebase_topic_relations, :freebase_topic_id
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class CreateFreebaseModelRelations < ActiveRecord::Migration
2
+ def change
3
+ create_table :freebase_model_relations do |t|
4
+ t.string :subject_type
5
+ t.integer :subject_id
6
+ t.string :property
7
+ t.string :object_type
8
+ t.integer :object_id
9
+
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :freebase_model_relations, [:subject_type, :subject_id, :property, :object_type, :object_id], :name => "freebase_topic_relations_triple"
14
+ end
15
+ end