michael-ken 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.
- data/.gitignore +23 -0
- data/README.textile +47 -7
- data/Rakefile +48 -22
- data/VERSION +1 -0
- data/lib/ken.rb +63 -24
- data/lib/ken/attribute.rb +6 -5
- data/lib/ken/property.rb +19 -16
- data/lib/ken/resource.rb +99 -94
- data/lib/ken/type.rb +3 -3
- data/lib/ken/util.rb +8 -4
- data/lib/ken/version.rb +1 -1
- data/lib/ken/view.rb +7 -7
- data/spec/fixtures/the_police.json +2 -2
- data/spec/integration/ken_spec.rb +37 -1
- data/spec/unit/resource_spec.rb +1 -1
- data/spec/unit/view_spec.rb +4 -2
- metadata +30 -36
- data/Manifest.txt +0 -34
- data/tasks/gemspec.rb +0 -23
- data/tasks/hoe.rb +0 -47
- data/tasks/install.rb +0 -13
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
test_log
|
2
|
+
pkg
|
3
|
+
pkg/*
|
4
|
+
*/pkg/*
|
5
|
+
bundle
|
6
|
+
bundle/*
|
7
|
+
doc
|
8
|
+
*.log
|
9
|
+
log
|
10
|
+
!log*.rb
|
11
|
+
*/log
|
12
|
+
log/*
|
13
|
+
*/log/*
|
14
|
+
coverage
|
15
|
+
*/coverage
|
16
|
+
lib/dm-more.rb
|
17
|
+
*.db
|
18
|
+
nbproject
|
19
|
+
.DS_Store
|
20
|
+
rspec_report.html
|
21
|
+
*.swp
|
22
|
+
_Yardoc
|
23
|
+
*/ri
|
data/README.textile
CHANGED
@@ -6,11 +6,11 @@ Ken is a Data Layer for Knowledge Representation.
|
|
6
6
|
|
7
7
|
It's being built to access the Metaweb Services supplied by Freebase.com.
|
8
8
|
Just born, the project’s goals are the provision of a concise API for querying and writing.
|
9
|
-
Therefore it wraps the Metaweb Architecture to smart Ruby Objects
|
9
|
+
Therefore it wraps the Metaweb Architecture to smart Ruby Objects.
|
10
10
|
|
11
11
|
You can navigate the Freebase Graph using a rubyish syntax.
|
12
12
|
|
13
|
-
|
13
|
+
If things go right, you should be able to use this library as a Data Layer (instead of or in addition to
|
14
14
|
ActiveRecord/DataMapper) for your Web Framework of choice (Merb, Rails).
|
15
15
|
|
16
16
|
|
@@ -52,7 +52,7 @@ Let's ask Ken what he knows about the British Band New Order.
|
|
52
52
|
</code>
|
53
53
|
</pre>
|
54
54
|
|
55
|
-
h3. Inspecting the
|
55
|
+
h3. Inspecting the Types
|
56
56
|
|
57
57
|
Every Resource can have multiple types.
|
58
58
|
|
@@ -67,7 +67,7 @@ Every Resource can have multiple types.
|
|
67
67
|
|
68
68
|
We can see that New Order is a member of Music Artist, Film Music Contributor, Broadcast Artist and other types.
|
69
69
|
|
70
|
-
h3. Inspecting a
|
70
|
+
h3. Inspecting a Type's properties
|
71
71
|
|
72
72
|
A type defines a set of properties to describe a Resource.
|
73
73
|
|
@@ -82,7 +82,7 @@ A type defines a set of properties to describe a Resource.
|
|
82
82
|
We get sets of Properties for each Type. The Type Musical Group has just one Property @/music/musical_group/member@
|
83
83
|
named Members Of Musical Group.
|
84
84
|
|
85
|
-
|
85
|
+
h3. Listing all Attributes
|
86
86
|
|
87
87
|
After inspecting a Resource's Types and Properties we now know what we could know. But actually we don't know nothing :)
|
88
88
|
So it's time to ask for the values of properties, the so called _Attributes_.
|
@@ -116,7 +116,7 @@ There are four kinds of Attributes.
|
|
116
116
|
In order to be able to use unique and non-unique Attributes in the same manner we always wrap the value of an Attribute
|
117
117
|
in a Collection, no matter if there's one value or there are many.
|
118
118
|
|
119
|
-
|
119
|
+
h3. Group Attributes by their Type using Views
|
120
120
|
|
121
121
|
|
122
122
|
<pre>
|
@@ -142,6 +142,46 @@ h4. Group Attributes by their Type using Views
|
|
142
142
|
</code>
|
143
143
|
</pre>
|
144
144
|
|
145
|
+
h3. Fetching multiple Resources using a query
|
146
|
+
|
147
|
+
As of now you can ask for multiple Resources by specifying a query.
|
148
|
+
|
149
|
+
<pre>
|
150
|
+
<code>
|
151
|
+
resources = Ken.all(:name => "Apple", :type => "/music/album")
|
152
|
+
# => [#<Resource id="/guid/9202a8c04000641f80000000031dae7c" name="Apple">,
|
153
|
+
#<Resource id="/guid/9202a8c04000641f8000000007ce31ec" name="Apple">]
|
154
|
+
</code>
|
155
|
+
</pre>
|
156
|
+
|
157
|
+
Keep in mind that only the top level of the query is mapped to a Collection of Resource Objects.
|
158
|
+
So asking for values in a nested level does not make sense. Use nested statements just for
|
159
|
+
lowering the top level result.
|
160
|
+
|
161
|
+
However you can instead navigate the normal way to figure out that values.
|
162
|
+
_But won't that require another query to triggered? Doubtful._
|
163
|
+
|
164
|
+
Let's look at a nested query:
|
165
|
+
|
166
|
+
<pre>
|
167
|
+
<code>
|
168
|
+
query = {
|
169
|
+
:directed_by => "George Lucas",
|
170
|
+
:starring => [
|
171
|
+
{
|
172
|
+
:actor => "Harrison Ford"
|
173
|
+
}
|
174
|
+
],
|
175
|
+
:type => "/film/film"
|
176
|
+
}
|
177
|
+
|
178
|
+
resources = Ken.all(query)
|
179
|
+
# => [#<Resource id="/en/star_wars_episode_iv_a_new_hope" name="Star Wars Episode IV: A New Hope">,
|
180
|
+
#<Resource id="/en/american_graffiti" name="American Graffiti">,
|
181
|
+
#<Resource id="/en/the_star_wars_holiday_special" name="The Star Wars Holiday Special">]
|
182
|
+
</code>
|
183
|
+
</pre>
|
184
|
+
|
145
185
|
h2. Status
|
146
186
|
|
147
187
|
Currently, the focus lies on inspecting Freebase Resources in a generic way. That's why
|
@@ -156,6 +196,7 @@ Chris "Eppsteins Freebase Library":http://github.com/chriseppstein/freebase/tree
|
|
156
196
|
h3. Features
|
157
197
|
|
158
198
|
* Fetching of single Resources
|
199
|
+
* Fetching of multiple Resources by specifying a query
|
159
200
|
* Type inspection
|
160
201
|
* Attributes inspection
|
161
202
|
* Views on Resources to group Attributes based on the Resource's types
|
@@ -164,7 +205,6 @@ h3. Features
|
|
164
205
|
h3. Roadmap
|
165
206
|
|
166
207
|
# Much more specs
|
167
|
-
# Support for querying of multiple Resources
|
168
208
|
# Better Type Support
|
169
209
|
# API for Set Based Browsing (see http://mqlx.com/~david/parallax/)
|
170
210
|
# Accessing Properties/Attributes directly (e.g. resource.genres )
|
data/Rakefile
CHANGED
@@ -1,30 +1,56 @@
|
|
1
|
-
require 'pathname'
|
2
1
|
require 'rubygems'
|
2
|
+
require 'rake'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "ken"
|
8
|
+
gem.summary = %Q{Ruby API for Accessing the Freebase}
|
9
|
+
gem.email = "ma[at]zive[dot]at"
|
10
|
+
gem.homepage = "http://github.com/michael/ken"
|
11
|
+
gem.authors = ["michael"]
|
12
|
+
# gem.files = FileList["[A-Z]*.*"]
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
+
end
|
8
15
|
|
9
|
-
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
18
|
+
end
|
10
19
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
# [ 'addressable', '~>2.0.1' ]
|
18
|
-
]
|
20
|
+
require 'rake/testtask'
|
21
|
+
Rake::TestTask.new(:test) do |test|
|
22
|
+
test.libs << 'lib' << 'test'
|
23
|
+
test.pattern = 'test/**/*_test.rb'
|
24
|
+
test.verbose = true
|
25
|
+
end
|
19
26
|
|
20
|
-
|
21
|
-
|
27
|
+
begin
|
28
|
+
require 'rcov/rcovtask'
|
29
|
+
Rcov::RcovTask.new do |test|
|
30
|
+
test.libs << 'test'
|
31
|
+
test.pattern = 'test/**/*_test.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
rescue LoadError
|
35
|
+
task :rcov do
|
36
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
37
|
+
end
|
38
|
+
end
|
22
39
|
|
23
|
-
PROJECT_NAME = 'ken'
|
24
|
-
PROJECT_URL = "http://github.com/michael/#{GEM_NAME}"
|
25
|
-
PROJECT_DESCRIPTION = PROJECT_SUMMARY = 'Ruby API for Accessing the Freebase'
|
26
40
|
|
27
|
-
|
28
|
-
|
29
|
-
|
41
|
+
task :default => :test
|
42
|
+
|
43
|
+
require 'rake/rdoctask'
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
if File.exist?('VERSION.yml')
|
46
|
+
config = YAML.load(File.read('VERSION.yml'))
|
47
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
48
|
+
else
|
49
|
+
version = ""
|
50
|
+
end
|
51
|
+
|
52
|
+
rdoc.rdoc_dir = 'rdoc'
|
53
|
+
rdoc.title = "ken #{version}"
|
54
|
+
rdoc.rdoc_files.include('README*')
|
55
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
30
56
|
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.3
|
data/lib/ken.rb
CHANGED
@@ -3,6 +3,7 @@ require 'rubygems'
|
|
3
3
|
require 'net/http'
|
4
4
|
require 'json'
|
5
5
|
require 'extlib'
|
6
|
+
require 'extlib/assertions'
|
6
7
|
require 'addressable/uri'
|
7
8
|
|
8
9
|
dir = Pathname(__FILE__).dirname.expand_path + 'ken'
|
@@ -25,9 +26,59 @@ Ken::Logger.new(STDOUT, :error)
|
|
25
26
|
Ken::Session.new('http://www.freebase.com', 'ma', 'xxxxx')
|
26
27
|
|
27
28
|
module Ken
|
29
|
+
|
30
|
+
extend Extlib::Assertions
|
31
|
+
|
32
|
+
|
33
|
+
# store query as a constant here.
|
34
|
+
# if the hash gets updated using
|
35
|
+
# #merge! or #update, this will mean
|
36
|
+
# that it actually stores the last
|
37
|
+
# query used. there are 2 sides to this.
|
38
|
+
# on the one hand, it isn't really a
|
39
|
+
# constant anymore (ruby doesn't complain)?
|
40
|
+
# on the other hand, there is no need to
|
41
|
+
# create a new object everytime a query is
|
42
|
+
# executed. maybe this is fine, maybe not,
|
43
|
+
# this needs to be discussed.
|
44
|
+
|
45
|
+
QUERY = query = {
|
46
|
+
# :id => id, # needs to be updated in instance mehtod
|
47
|
+
:name => nil,
|
48
|
+
:"ken:type" => [{
|
49
|
+
:id => nil,
|
50
|
+
:name => nil,
|
51
|
+
:properties => [{
|
52
|
+
:id => nil,
|
53
|
+
:name => nil,
|
54
|
+
:expected_type => nil,
|
55
|
+
:unique => nil,
|
56
|
+
:reverse_property => nil,
|
57
|
+
:master_property => nil,
|
58
|
+
}]
|
59
|
+
}]
|
60
|
+
}
|
61
|
+
|
62
|
+
# Executes an Mql Query against the Freebase API and returns the result as
|
63
|
+
# a <tt>Collection</tt> of <tt>Resources</tt>.
|
64
|
+
#
|
65
|
+
# == Examples
|
66
|
+
#
|
67
|
+
# Ken.all(:name => "Apple", :type => "/music/album")
|
68
|
+
#
|
69
|
+
# Ken.all(
|
70
|
+
# :directed_by => "George Lucas",
|
71
|
+
# :starring => [{
|
72
|
+
# :actor => "Harrison Ford"
|
73
|
+
# }],
|
74
|
+
# :type => "/film/film"
|
75
|
+
# )
|
76
|
+
# @api public
|
28
77
|
def self.all(options = {})
|
29
|
-
|
30
|
-
|
78
|
+
assert_kind_of 'options', options, Hash
|
79
|
+
query = { :name => nil }.merge!(options).merge!(:id => nil) # collection queries MUST have :id => nil, no?
|
80
|
+
result = Ken.session.mqlread([ query ])
|
81
|
+
Ken::Collection.new(result.map { |r| Ken::Resource.new(r) })
|
31
82
|
end
|
32
83
|
|
33
84
|
|
@@ -37,28 +88,16 @@ module Ken
|
|
37
88
|
# == Examples
|
38
89
|
#
|
39
90
|
# Ken.get('/en/the_police') => #<Resource id="/en/the_police" name="The Police">
|
91
|
+
# @api public
|
40
92
|
def self.get(id)
|
41
|
-
|
42
|
-
raise ArgumentError
|
43
|
-
|
44
|
-
|
45
|
-
:id => id,
|
46
|
-
:name => nil,
|
47
|
-
:type => [{
|
48
|
-
:id => nil,
|
49
|
-
:name => nil,
|
50
|
-
:properties => [{
|
51
|
-
:id => nil,
|
52
|
-
:name => nil,
|
53
|
-
:expected_type => nil,
|
54
|
-
:unique => nil,
|
55
|
-
:reverse_property => nil,
|
56
|
-
:master_property => nil,
|
57
|
-
}]
|
58
|
-
}]
|
59
|
-
}
|
60
|
-
|
61
|
-
result = Ken.session.mqlread(query)
|
62
|
-
return Ken::Resource.new(result)
|
93
|
+
assert_kind_of 'id', id, String
|
94
|
+
raise ArgumentError, "id must be in /type/object/id format" unless valid_id_attribute?(id)
|
95
|
+
result = Ken.session.mqlread(QUERY.merge!(:id => id))
|
96
|
+
Ken::Resource.new(result)
|
63
97
|
end
|
98
|
+
|
99
|
+
def self.valid_id_attribute?(id)
|
100
|
+
id =~ /\/\w+/
|
101
|
+
end
|
102
|
+
|
64
103
|
end # module Ken
|
data/lib/ken/attribute.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
module Ken
|
2
2
|
class Attribute
|
3
|
+
|
4
|
+
include Extlib::Assertions
|
5
|
+
|
3
6
|
attr_reader :property
|
4
7
|
|
5
8
|
# initializes a resource by json result
|
6
9
|
def initialize(data, property)
|
7
|
-
|
8
|
-
|
9
|
-
@data = data
|
10
|
-
@property = property # belongs to a property
|
11
|
-
self
|
10
|
+
assert_kind_of 'data', data, Array
|
11
|
+
assert_kind_of 'property', property, Ken::Property
|
12
|
+
@data, @property = data, property
|
12
13
|
end
|
13
14
|
|
14
15
|
def self.create(data, property)
|
data/lib/ken/property.rb
CHANGED
@@ -1,12 +1,25 @@
|
|
1
1
|
module Ken
|
2
2
|
class Property
|
3
3
|
|
4
|
+
include Extlib::Assertions
|
5
|
+
|
6
|
+
VALUE_TYPES = %w{
|
7
|
+
/type/id
|
8
|
+
/type/int
|
9
|
+
/type/float
|
10
|
+
/type/boolean
|
11
|
+
/type/text
|
12
|
+
/type/rawstring
|
13
|
+
/type/uri
|
14
|
+
/type/datetime
|
15
|
+
/type/key
|
16
|
+
}
|
17
|
+
|
4
18
|
# initializes a resource by json result
|
5
19
|
def initialize(data, type)
|
6
|
-
|
7
|
-
|
8
|
-
@type = type
|
9
|
-
self
|
20
|
+
assert_kind_of 'data', data, Hash
|
21
|
+
assert_kind_of 'type', type, Ken::Type
|
22
|
+
@data, @type = data, type
|
10
23
|
end
|
11
24
|
|
12
25
|
# @api public
|
@@ -56,23 +69,13 @@ module Ken
|
|
56
69
|
# returns true if the property is an object type
|
57
70
|
# @api public
|
58
71
|
def object_type?
|
59
|
-
|
60
|
-
/type/id
|
61
|
-
/type/int
|
62
|
-
/type/float
|
63
|
-
/type/boolean
|
64
|
-
/type/text
|
65
|
-
/type/rawstring
|
66
|
-
/type/uri
|
67
|
-
/type/datetime
|
68
|
-
/type/key
|
69
|
-
}.include?(expected_type)
|
72
|
+
!value_type?
|
70
73
|
end
|
71
74
|
|
72
75
|
# returns true if the property is a value type
|
73
76
|
# @api public
|
74
77
|
def value_type?
|
75
|
-
|
78
|
+
VALUE_TYPES.include?(expected_type)
|
76
79
|
end
|
77
80
|
|
78
81
|
# @api public
|
data/lib/ken/resource.rb
CHANGED
@@ -1,107 +1,56 @@
|
|
1
1
|
module Ken
|
2
2
|
class Resource
|
3
|
-
# initializes a resource by json result
|
4
|
-
def initialize(data)
|
5
|
-
return nil unless data
|
6
|
-
raise "error" unless data.kind_of?(Hash)
|
7
|
-
|
8
|
-
# intialize lazy if there is no type supplied
|
9
|
-
@schema_loaded = false
|
10
|
-
@attributes_loaded = false
|
11
|
-
@data = data
|
12
|
-
|
13
|
-
self
|
14
|
-
end
|
15
|
-
|
16
|
-
def schema_loaded?
|
17
|
-
@schema_loaded
|
18
|
-
end
|
19
|
-
|
20
|
-
def attributes_loaded?
|
21
|
-
@attributes_loaded
|
22
|
-
end
|
23
3
|
|
24
|
-
|
25
|
-
# fetching all objects regardless of the type
|
26
|
-
# check this http://lists.freebase.com/pipermail/developers/2007-December/001022.html
|
27
|
-
|
28
|
-
query = {
|
29
|
-
:"/type/reflect/any_master" => [
|
30
|
-
{
|
31
|
-
:id => nil,
|
32
|
-
:link => nil,
|
33
|
-
:name => nil
|
34
|
-
}
|
35
|
-
],
|
36
|
-
:"/type/reflect/any_reverse" => [
|
37
|
-
{
|
38
|
-
:id => nil,
|
39
|
-
:link => nil,
|
40
|
-
:name => nil
|
41
|
-
}
|
42
|
-
],
|
43
|
-
:"/type/reflect/any_value" => [
|
44
|
-
{
|
45
|
-
:link => nil,
|
46
|
-
:value => nil
|
47
|
-
# :lang => "/lang/en",
|
48
|
-
# :type => "/type/text"
|
49
|
-
}
|
50
|
-
],
|
51
|
-
:id => id
|
52
|
-
}
|
53
|
-
|
54
|
-
Ken.session.mqlread(query)
|
55
|
-
end
|
4
|
+
include Extlib::Assertions
|
56
5
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
raw_attributes.merge!(Ken::Util.convert_hash(data["/type/reflect/any_value"]))
|
63
|
-
@attributes = {}
|
64
|
-
raw_attributes.each_pair do |a, d|
|
65
|
-
properties.select { |p| p.id == a}.each do |p|
|
66
|
-
@attributes[p.id] = Ken::Attribute.create(d, p)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# reverse properties
|
71
|
-
raw_attributes = Ken::Util.convert_hash(data["/type/reflect/any_reverse"])
|
72
|
-
raw_attributes.each_pair do |a, d|
|
73
|
-
properties.select { |p| p.master_property == a}.each do |p|
|
74
|
-
@attributes[p.id] = Ken::Attribute.create(d, p)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
@attributes_loaded = true
|
79
|
-
end
|
80
|
-
|
81
|
-
def fetch_schema
|
82
|
-
query = {
|
83
|
-
:id => id,
|
6
|
+
FETCH_SCHEMA_QUERY = {
|
7
|
+
# :id => id, # needs to be merge!d in instance method
|
8
|
+
:name => nil,
|
9
|
+
:"ken:type" => [{
|
10
|
+
:id => nil,
|
84
11
|
:name => nil,
|
85
|
-
:
|
12
|
+
:properties => [{
|
86
13
|
:id => nil,
|
87
14
|
:name => nil,
|
88
|
-
:
|
89
|
-
|
90
|
-
:name => nil,
|
91
|
-
:expected_type => nil,
|
92
|
-
:unique => nil
|
93
|
-
}]
|
15
|
+
:expected_type => nil,
|
16
|
+
:unique => nil
|
94
17
|
}]
|
95
|
-
}
|
18
|
+
}]
|
19
|
+
}
|
20
|
+
|
21
|
+
FETCH_ATTRIBUTES_QUERY = {
|
22
|
+
:"/type/reflect/any_master" => [
|
23
|
+
{
|
24
|
+
:id => nil,
|
25
|
+
:link => nil,
|
26
|
+
:name => nil
|
27
|
+
}
|
28
|
+
],
|
29
|
+
:"/type/reflect/any_reverse" => [
|
30
|
+
{
|
31
|
+
:id => nil,
|
32
|
+
:link => nil,
|
33
|
+
:name => nil
|
34
|
+
}
|
35
|
+
],
|
36
|
+
:"/type/reflect/any_value" => [
|
37
|
+
{
|
38
|
+
:link => nil,
|
39
|
+
:value => nil
|
40
|
+
# :lang => "/lang/en",
|
41
|
+
# :type => "/type/text"
|
42
|
+
}
|
43
|
+
],
|
96
44
|
|
97
|
-
|
98
|
-
|
45
|
+
# :id => id # needs to be merg!d in instance method
|
46
|
+
}
|
99
47
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
48
|
+
|
49
|
+
# initializes a resource by json result
|
50
|
+
def initialize(data)
|
51
|
+
assert_kind_of 'data', data, Hash
|
52
|
+
# intialize lazy if there is no type supplied
|
53
|
+
@schema_loaded, @attributes_loaded, @data = false, false, data
|
105
54
|
end
|
106
55
|
|
107
56
|
# @api public
|
@@ -153,6 +102,62 @@ module Ken
|
|
153
102
|
load_attributes! unless attributes_loaded?
|
154
103
|
@attributes.values
|
155
104
|
end
|
105
|
+
|
106
|
+
# returns true if type information is already loaded
|
107
|
+
# @api public
|
108
|
+
def schema_loaded?
|
109
|
+
@schema_loaded
|
110
|
+
end
|
111
|
+
|
112
|
+
# returns true if attributes are already loaded
|
113
|
+
# @api public
|
114
|
+
def attributes_loaded?
|
115
|
+
@attributes_loaded
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
def fetch_attributes
|
120
|
+
# fetching all objects regardless of the type
|
121
|
+
# check this http://lists.freebase.com/pipermail/developers/2007-December/001022.html
|
122
|
+
Ken.session.mqlread(FETCH_ATTRIBUTES_QUERY.merge!(:id => id))
|
123
|
+
end
|
124
|
+
|
125
|
+
def load_attributes!
|
126
|
+
data = @data["ken:attribute"] || fetch_attributes
|
127
|
+
|
128
|
+
# master & value attributes
|
129
|
+
raw_attributes = Ken::Util.convert_hash(data["/type/reflect/any_master"])
|
130
|
+
raw_attributes.merge!(Ken::Util.convert_hash(data["/type/reflect/any_value"]))
|
131
|
+
@attributes = {}
|
132
|
+
raw_attributes.each_pair do |a, d|
|
133
|
+
properties.select { |p| p.id == a}.each do |p|
|
134
|
+
@attributes[p.id] = Ken::Attribute.create(d, p)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# reverse properties
|
139
|
+
raw_attributes = Ken::Util.convert_hash(data["/type/reflect/any_reverse"])
|
140
|
+
raw_attributes.each_pair do |a, d|
|
141
|
+
properties.select { |p| p.master_property == a}.each do |p|
|
142
|
+
@attributes[p.id] = Ken::Attribute.create(d, p)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
@attributes_loaded = true
|
147
|
+
end
|
148
|
+
|
149
|
+
def fetch_schema
|
150
|
+
Ken.session.mqlread(FETCH_SCHEMA_QUERY.merge!(:id => id))["ken:type"]
|
151
|
+
end
|
152
|
+
|
153
|
+
# loads the resources metainfo
|
154
|
+
# @api private
|
155
|
+
def load_schema!
|
156
|
+
@data["ken:type"] ||= fetch_schema
|
157
|
+
@types = Ken::Collection.new(@data["ken:type"].map { |type| Ken::Type.new(type) })
|
158
|
+
@schema_loaded = true
|
159
|
+
end
|
160
|
+
|
156
161
|
|
157
162
|
end # class Resource
|
158
163
|
end # module Ken
|
data/lib/ken/type.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
module Ken
|
2
2
|
class Type
|
3
3
|
|
4
|
+
include Extlib::Assertions
|
5
|
+
|
4
6
|
# initializes a resource by json result
|
5
7
|
def initialize(data)
|
6
|
-
|
7
|
-
|
8
|
+
assert_kind_of 'data', data, Hash
|
8
9
|
@data = data
|
9
|
-
self
|
10
10
|
end
|
11
11
|
|
12
12
|
# access property info
|
data/lib/ken/util.rb
CHANGED
@@ -2,11 +2,15 @@ module Ken
|
|
2
2
|
module Util
|
3
3
|
# magic hash conversion
|
4
4
|
def convert_hash(source)
|
5
|
-
result
|
6
|
-
|
7
|
-
|
5
|
+
source.inject({}) do |result, item|
|
6
|
+
if result[item["link"]]
|
7
|
+
result[item["link"]] << { "id" => item["id"], "name" => item["name"], "value" => item["value"] }
|
8
|
+
else
|
9
|
+
result[item["link"]] = []
|
10
|
+
result[item["link"]] << { "id" => item["id"], "name" => item["name"], "value" => item["value"] }
|
11
|
+
end
|
12
|
+
result
|
8
13
|
end
|
9
|
-
result
|
10
14
|
end
|
11
15
|
module_function :convert_hash
|
12
16
|
end
|
data/lib/ken/version.rb
CHANGED
data/lib/ken/view.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# provides an interface to view a resource as a specific type
|
2
2
|
# provides an interface for working with attributes, properties
|
3
3
|
module Ken
|
4
|
-
class View
|
4
|
+
class View
|
5
|
+
|
6
|
+
include Extlib::Assertions
|
7
|
+
|
5
8
|
# initializes a resource by json result
|
6
9
|
def initialize(resource, type)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
@resource = resource # belongs to a resource
|
11
|
-
@type = type # belongs to a type
|
12
|
-
self
|
10
|
+
assert_kind_of 'resource', resource, Ken::Resource
|
11
|
+
assert_kind_of 'type', type, Ken::Type
|
12
|
+
@resource, @type = resource, type
|
13
13
|
end
|
14
14
|
|
15
15
|
# @api public
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"id" : "/en/the_police",
|
3
3
|
"name" : "The Police",
|
4
|
-
"type" : [
|
4
|
+
"ken:type" : [
|
5
5
|
{
|
6
6
|
"id" : "/music/artist",
|
7
7
|
"name" : "Musical Artist",
|
@@ -189,7 +189,7 @@
|
|
189
189
|
]
|
190
190
|
}
|
191
191
|
],
|
192
|
-
"attribute" : {
|
192
|
+
"ken:attribute" : {
|
193
193
|
"/type/reflect/any_master" : [
|
194
194
|
{
|
195
195
|
"id" : "/boot/all_permission",
|
@@ -9,12 +9,48 @@ describe Ken do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
describe "Ken.get('/en/the_police')" do
|
12
|
-
it
|
12
|
+
it "should return a Ken::Resource" do
|
13
13
|
the_police = Ken.get("/en/the_police")
|
14
14
|
the_police.should be_kind_of(Ken::Resource)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
describe "Ken.all" do
|
19
|
+
it "should return a Ken::Collection of Ken::Resources" do
|
20
|
+
resources = Ken.all(:name => "Apple")
|
21
|
+
resources.should be_kind_of(Ken::Collection)
|
22
|
+
resources.first.should be_kind_of(Ken::Resource)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should work with a limit specified" do
|
26
|
+
resources = Ken.all(:name => "Apple", :limit => 3)
|
27
|
+
resources.should have(3).items
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should work with a type specified" do
|
31
|
+
resources = Ken.all(:name => "Apple", :type => "/music/album")
|
32
|
+
resources.should have_at_least(1).items
|
33
|
+
resources.each {|r| r.types.select {|t| t.id == "/music/album"}.should have(1).items }
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should understand nested queries" do
|
37
|
+
query = {
|
38
|
+
:directed_by => "George Lucas",
|
39
|
+
:starring => [
|
40
|
+
{
|
41
|
+
:actor => "Harrison Ford"
|
42
|
+
}
|
43
|
+
],
|
44
|
+
:type => "/film/film"
|
45
|
+
}
|
46
|
+
|
47
|
+
resources = Ken.all(query)
|
48
|
+
resources.should have(3).items
|
49
|
+
resources.first.name.should == "Star Wars Episode IV: A New Hope"
|
50
|
+
resources.last.name.should == "The Star Wars Holiday Special"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
18
54
|
describe "Ken::Resource" do
|
19
55
|
before :all do
|
20
56
|
@the_police = Ken.get("/en/the_police")
|
data/spec/unit/resource_spec.rb
CHANGED
@@ -5,7 +5,7 @@ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
|
|
5
5
|
describe Ken::Resource do
|
6
6
|
|
7
7
|
before :each do
|
8
|
-
Ken::Logger.new(STDOUT, :info)
|
8
|
+
# Ken::Logger.new(STDOUT, :info)
|
9
9
|
# Ken::Session.new('http://www.freebase.com', 'ma', 'xxxxx')
|
10
10
|
data = load_fixture('the_police')
|
11
11
|
@the_police = Ken::Resource.new(data)
|
data/spec/unit/view_spec.rb
CHANGED
@@ -7,20 +7,22 @@ describe Ken::View do
|
|
7
7
|
Ken::Logger.new(STDOUT, :info)
|
8
8
|
data = load_fixture('the_police')
|
9
9
|
@the_police = Ken::Resource.new(data)
|
10
|
-
|
11
10
|
@view = @the_police.views.first
|
12
11
|
end
|
13
12
|
|
14
13
|
it "should have a type" do
|
15
14
|
@view.type.should_not be_nil
|
15
|
+
@view.type.should be_kind_of(Ken::Type)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should have properties" do
|
19
19
|
@view.properties.should_not be_nil
|
20
|
+
@view.properties.each { |p| p.should be_kind_of(Ken::Property)}
|
20
21
|
end
|
21
22
|
|
22
23
|
it "should have attributes" do
|
23
|
-
@view.
|
24
|
+
@view.attributes.should_not be_nil
|
25
|
+
@view.attributes.each { |p| p.should be_kind_of(Ken::Attribute)}
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
metadata
CHANGED
@@ -1,47 +1,37 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: michael-ken
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- michael
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-05-14 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: "0"
|
24
|
-
version:
|
25
|
-
description: Ruby API for accessing Freebase
|
26
|
-
email:
|
27
|
-
- ma [a] zive [d] at
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: ma[at]zive[dot]at
|
28
18
|
executables: []
|
29
19
|
|
30
20
|
extensions: []
|
31
21
|
|
32
22
|
extra_rdoc_files:
|
33
|
-
- README.txt
|
34
23
|
- LICENSE
|
35
|
-
-
|
36
|
-
-
|
24
|
+
- README.textile
|
25
|
+
- README.txt
|
37
26
|
files:
|
27
|
+
- .gitignore
|
38
28
|
- History.txt
|
39
29
|
- LICENSE
|
40
|
-
- Manifest.txt
|
41
|
-
- README.txt
|
42
30
|
- README.textile
|
31
|
+
- README.txt
|
43
32
|
- Rakefile
|
44
33
|
- TODO
|
34
|
+
- VERSION
|
45
35
|
- examples/artist.rb
|
46
36
|
- lib/ken.rb
|
47
37
|
- lib/ken/attribute.rb
|
@@ -54,27 +44,23 @@ files:
|
|
54
44
|
- lib/ken/util.rb
|
55
45
|
- lib/ken/version.rb
|
56
46
|
- lib/ken/view.rb
|
47
|
+
- spec/fixtures/music_artist.json
|
48
|
+
- spec/fixtures/the_police.json
|
49
|
+
- spec/integration/ken_spec.rb
|
50
|
+
- spec/spec.opts
|
51
|
+
- spec/spec_helper.rb
|
57
52
|
- spec/unit/attribute_spec.rb
|
58
53
|
- spec/unit/property_spec.rb
|
59
54
|
- spec/unit/resource_spec.rb
|
60
55
|
- spec/unit/session_spec.rb
|
61
56
|
- spec/unit/type_spec.rb
|
62
57
|
- spec/unit/view_spec.rb
|
63
|
-
- spec/integration/ken_spec.rb
|
64
|
-
- spec/fixtures/music_artist.json
|
65
|
-
- spec/fixtures/the_police.json
|
66
|
-
- spec/spec.opts
|
67
|
-
- spec/spec_helper.rb
|
68
|
-
- tasks/hoe.rb
|
69
|
-
- tasks/install.rb
|
70
58
|
- tasks/spec.rb
|
71
|
-
- tasks/gemspec.rb
|
72
59
|
has_rdoc: true
|
73
60
|
homepage: http://github.com/michael/ken
|
74
61
|
post_install_message:
|
75
62
|
rdoc_options:
|
76
|
-
- --
|
77
|
-
- README.txt
|
63
|
+
- --charset=UTF-8
|
78
64
|
require_paths:
|
79
65
|
- lib
|
80
66
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -91,10 +77,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
77
|
version:
|
92
78
|
requirements: []
|
93
79
|
|
94
|
-
rubyforge_project:
|
80
|
+
rubyforge_project:
|
95
81
|
rubygems_version: 1.2.0
|
96
82
|
signing_key:
|
97
83
|
specification_version: 2
|
98
|
-
summary: Ruby API for
|
99
|
-
test_files:
|
100
|
-
|
84
|
+
summary: Ruby API for Accessing the Freebase
|
85
|
+
test_files:
|
86
|
+
- spec/integration/ken_spec.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
- spec/unit/attribute_spec.rb
|
89
|
+
- spec/unit/property_spec.rb
|
90
|
+
- spec/unit/resource_spec.rb
|
91
|
+
- spec/unit/session_spec.rb
|
92
|
+
- spec/unit/type_spec.rb
|
93
|
+
- spec/unit/view_spec.rb
|
94
|
+
- examples/artist.rb
|
data/Manifest.txt
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
History.txt
|
2
|
-
LICENSE
|
3
|
-
Manifest.txt
|
4
|
-
README.textile
|
5
|
-
README.txt
|
6
|
-
Rakefile
|
7
|
-
TODO
|
8
|
-
examples/artist.rb
|
9
|
-
lib/ken.rb
|
10
|
-
lib/ken/attribute.rb
|
11
|
-
lib/ken/collection.rb
|
12
|
-
lib/ken/logger.rb
|
13
|
-
lib/ken/property.rb
|
14
|
-
lib/ken/resource.rb
|
15
|
-
lib/ken/session.rb
|
16
|
-
lib/ken/type.rb
|
17
|
-
lib/ken/util.rb
|
18
|
-
lib/ken/version.rb
|
19
|
-
lib/ken/view.rb
|
20
|
-
spec/fixtures/music_artist.json
|
21
|
-
spec/fixtures/the_police.json
|
22
|
-
spec/integration/ken_spec.rb
|
23
|
-
spec/spec.opts
|
24
|
-
spec/spec_helper.rb
|
25
|
-
spec/unit/attribute_spec.rb
|
26
|
-
spec/unit/property_spec.rb
|
27
|
-
spec/unit/resource_spec.rb
|
28
|
-
spec/unit/session_spec.rb
|
29
|
-
spec/unit/type_spec.rb
|
30
|
-
spec/unit/view_spec.rb
|
31
|
-
tasks/gemspec.rb
|
32
|
-
tasks/hoe.rb
|
33
|
-
tasks/install.rb
|
34
|
-
tasks/spec.rb
|
data/tasks/gemspec.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
desc "Generate gemspec"
|
2
|
-
task :gemspec do |x|
|
3
|
-
# Clean up extraneous files before checking manifest
|
4
|
-
%x[rake clean]
|
5
|
-
|
6
|
-
# Check the manifest before generating the gemspec
|
7
|
-
manifest = %x[rake check_manifest]
|
8
|
-
manifest.gsub!("(in /usr/local/projects/dm/dm-core)\n", "")
|
9
|
-
|
10
|
-
unless manifest.empty?
|
11
|
-
print "\n", "#"*68, "\n"
|
12
|
-
print <<-EOS
|
13
|
-
Manifest.txt is not up-to-date. Please review the changes below.
|
14
|
-
If the changes are correct, run 'rake check_manifest | patch'
|
15
|
-
and then run this command again.
|
16
|
-
EOS
|
17
|
-
print "#"*68, "\n\n"
|
18
|
-
puts manifest
|
19
|
-
else
|
20
|
-
%x[rake debug_gem > #{GEM_NAME}.gemspec]
|
21
|
-
puts "Successfully created gemspec for #{GEM_NAME}!"
|
22
|
-
end
|
23
|
-
end
|
data/tasks/hoe.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'hoe'
|
2
|
-
|
3
|
-
@config_file = "~/.rubyforge/user-config.yml"
|
4
|
-
@config = nil
|
5
|
-
RUBYFORGE_USERNAME = "unknown"
|
6
|
-
def rubyforge_username
|
7
|
-
unless @config
|
8
|
-
begin
|
9
|
-
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
10
|
-
rescue
|
11
|
-
puts <<-EOS
|
12
|
-
ERROR: No rubyforge config file found: #{@config_file}
|
13
|
-
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
14
|
-
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
15
|
-
EOS
|
16
|
-
exit
|
17
|
-
end
|
18
|
-
end
|
19
|
-
RUBYFORGE_USERNAME.replace @config["username"]
|
20
|
-
end
|
21
|
-
|
22
|
-
# Remove hoe dependency
|
23
|
-
class Hoe
|
24
|
-
def extra_dev_deps
|
25
|
-
@extra_dev_deps.reject! { |dep| dep[0] == "hoe" }
|
26
|
-
@extra_dev_deps
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
hoe = Hoe.new(GEM_NAME, GEM_VERSION) do |p|
|
31
|
-
|
32
|
-
p.developer(AUTHOR, EMAIL)
|
33
|
-
|
34
|
-
p.description = PROJECT_DESCRIPTION
|
35
|
-
p.summary = PROJECT_SUMMARY
|
36
|
-
p.url = PROJECT_URL
|
37
|
-
|
38
|
-
p.rubyforge_name = PROJECT_NAME if PROJECT_NAME
|
39
|
-
|
40
|
-
p.clean_globs |= GEM_CLEAN
|
41
|
-
p.spec_extras = GEM_EXTRAS if GEM_EXTRAS
|
42
|
-
|
43
|
-
GEM_DEPENDENCIES.each do |dep|
|
44
|
-
p.extra_deps << dep
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
data/tasks/install.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
def sudo_gem(cmd)
|
2
|
-
sh "#{SUDO} #{RUBY} -S gem #{cmd}", :verbose => false
|
3
|
-
end
|
4
|
-
|
5
|
-
desc "Install #{GEM_NAME} #{GEM_VERSION}"
|
6
|
-
task :install => [ :package ] do
|
7
|
-
sudo_gem "install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
|
8
|
-
end
|
9
|
-
|
10
|
-
desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
|
11
|
-
task :uninstall => [ :clobber ] do
|
12
|
-
sudo_gem "uninstall #{GEM_NAME} -v#{GEM_VERSION} -Ix"
|
13
|
-
end
|