activesesame 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.txt ADDED
File without changes
data/README.txt ADDED
@@ -0,0 +1,25 @@
1
+ See the wiki for details:
2
+ http://wiki.github.com/mwarnock/activesesame
3
+
4
+ (The MIT License)
5
+
6
+ Copyright (c) 2008 ActiveSesame
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining
9
+ a copy of this software and associated documentation files (the
10
+ 'Software'), to deal in the Software without restriction, including
11
+ without limitation the rights to use, copy, modify, merge, publish,
12
+ distribute, sublicense, and/or sell copies of the Software, and to
13
+ permit persons to whom the Software is furnished to do so, subject to
14
+ the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be
17
+ included in all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
20
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require 'rake'
2
+
3
+ Dir['tasks/*.rake'].each { |rake| load rake }
data/init.rb ADDED
File without changes
data/install.rb ADDED
File without changes
@@ -0,0 +1,7 @@
1
+ module ActiveSesame
2
+ #defined?("ACTIVE_SESAME_ROOT") ? path = ACTIVE_SEASAME_ROOT :
3
+ path = File.dirname(__FILE__)
4
+ %w(monkey_patches rdf_constants result_parser support repository transaction_builder ontology base behaviors owl_thing).each do |f|
5
+ require File.join(path, f)
6
+ end
7
+ end
@@ -0,0 +1,235 @@
1
+ module ActiveSesame
2
+ class Base
3
+ ActiveSesame::MonkeyPatches #Run The monkey Patches
4
+
5
+ def Base.inherited(subClass)
6
+ ############################################
7
+ ####### Generic Attribute Handling ########
8
+ ############################################
9
+
10
+ #Create class variables that are independant of the super class
11
+ class << self
12
+ attr_accessor :rdf_class, :triple_store_id, :base_uri, :unique_property, :unique_property_type, :attributes, :attribute_method_names
13
+ attr_accessor :connection
14
+ attr_accessor :simple_attributes, :simple_method_names
15
+ attr_accessor :complex_attributes, :complex_method_names
16
+ end
17
+
18
+ #Set the Default values for the inheritable class accessors
19
+ subClass.rdf_class = subClass.name.split("::").last.to_s
20
+ subClass.triple_store_id = "study-stash"
21
+ subClass.set_base_uri "http://study-stash.radiology.umm.edu/ontologies/study-stash.owl#"
22
+ subClass.unique_property = subClass.name
23
+ subClass.unique_property_type = RDFConstants.class_to_match_hash[String]
24
+ subClass.attributes = {}
25
+ subClass.attribute_method_names = []
26
+ subClass.simple_attributes = {}
27
+ subClass.simple_method_names = []
28
+ subClass.complex_attributes = {}
29
+ subClass.complex_method_names = []
30
+ subClass.connection = Repository.new
31
+
32
+ #Create the attribute accessors for instances
33
+ attr_accessor :attribute_table, :instance, :transaction_triples
34
+
35
+ def subClass.base_uri_location
36
+ uri_with_quacks = self.base_uri.split(" ").last
37
+ uri_with_quacks.slice(1,uri_with_quacks.length-2)
38
+ end
39
+
40
+ def subClass.set_rdf_class(new_class_name)
41
+ self.rdf_class = new_class_name.to_s
42
+ self.set_attributes
43
+ end
44
+
45
+ def subClass.set_triple_store_id(new_id)
46
+ self.triple_store_id = new_id.to_s
47
+ self.set_attributes
48
+ end
49
+
50
+ def subClass.set_unique_property(new_property_name, type)
51
+ self.unique_property = new_property_name.to_s
52
+ self.unique_property_type = RDFConstants.class_to_match_hash[type]
53
+ end
54
+
55
+ def subClass.set_attributes
56
+ #puts "SELECT ?property_name ?property_type WHERE { ?property_name rdfs:domain <#{rdf_class}>; rdfs:range ?property_type }"
57
+ self.attributes = ResultParser.hash_values(self.connection.find_by_sparql("SELECT ?property_name ?property_type WHERE { ?property_name rdfs:domain <#{rdf_class}>; rdfs:range ?property_type }"))
58
+ self.attributes.each do |uri,type|
59
+ if RDFConstants.literals.include?(type)
60
+ self.simple_attributes[uri] = type
61
+ self.simple_method_names << Support.uri_to_sym(uri)
62
+ else
63
+ self.complex_attributes[uri] = type
64
+ self.complex_method_names << Support.uri_to_sym(uri).to_s.pluralize
65
+ end
66
+ end
67
+ self.generate_methods
68
+ self.attributes
69
+ end
70
+
71
+ def subClass.set_attribute_method_names
72
+ self.attribute_method_names = self.attributes.keys.collect {|key| Support.uri_to_sym(key) }
73
+ end
74
+
75
+ ####################################
76
+ ######## Validation Tools #########
77
+ ####################################
78
+
79
+ def subClass.validate(instance)
80
+ self.find(instance.instance) ? false : true
81
+ end
82
+
83
+ ###########################################
84
+ ######## Dynamic Method Generation ########
85
+ ###########################################
86
+
87
+ #creates accessor methods and initiates other method Generators
88
+ def subClass.generate_methods
89
+ attr_accessor *(self.simple_method_names) unless self.simple_method_names.empty?
90
+ self.generate_find_methods
91
+ self.generate_complex_methods
92
+ end
93
+
94
+ #Generates methods for selecting all the uri (complex) properties associated with a specific instance
95
+ def subClass.generate_complex_methods
96
+ self.complex_attributes.each do |uri,type|
97
+ method = Support.uri_to_sym(uri)
98
+ define_method(method.to_s.pluralize) do
99
+ if Kernel.const_get(Support.uri_to_sym(type))
100
+ ResultParser.singular_values(self.class.find_by_sparql("SELECT ?object WHERE { <#{self.instance}> <#{uri}> ?object }")).collect {|foreign_uri| Kernel.const_get(Support.uri_to_sym(type)).find(foreign_uri) }
101
+ else
102
+ "No Class Defined for: #{Support.uri_to_sym(type)}"
103
+ end
104
+ end
105
+ define_method("add_" + method.to_s.pluralize) do |instance_or_object|
106
+ instance_or_object.class == String ? instance = instance_or_object : instance = instance_or_object.instance
107
+ if Kernel.const_get(Support.uri_to_sym(type))
108
+ self.class.group_save(ActiveSesame::TransactionBuilder.build_triple(self.instance, uri, instance))
109
+ end
110
+ end
111
+ attr_accessor (method.to_s.pluralize + "_for_" + self.name.downcase).to_sym
112
+ end
113
+ end
114
+
115
+ #Generates all the find_by_property methods for the inherited class
116
+ def subClass.generate_find_methods
117
+ self.simple_method_names.each do |m|
118
+ self.class_eval(
119
+ "def self.find_by_#{m} (value)
120
+ #puts \"SELECT \#{self.attributes_to_sparql_vars} WHERE { ?instance <#{m}> '\#{value}'^^\#{ActiveSesame::RDFConstants.class_to_match_hash[value.class]} . \#{self.attributes_to_sparql_patterns}}\"
121
+ self.new(ResultParser.tableize(self.connection.find_by_sparql(\"SELECT \#{self.attributes_to_sparql_vars} WHERE { ?instance <#{m}> '\#{value}' . \#{self.attributes_to_sparql_patterns}}\")).first)
122
+ #puts self.connection.find_by_sparql(\"SELECT \#{self.attributes_to_sparql_vars} WHERE { ?instance <#{m}> '\#{value}'^^\#{ActiveSesame::RDFConstants.class_to_match_hash[value.class]} . \#{self.attributes_to_sparql_patterns}}\")
123
+ end") #When you fix the datatype attributes in allegro graph you need to change this function or you'll get nils
124
+ end
125
+ end
126
+
127
+
128
+ ######################################
129
+ ######## SPARQL Query Helpers ########
130
+ ######################################
131
+
132
+ #Converts the simple method names list into a series of sparql patterns for the WHERE clause
133
+ def subClass.attributes_to_sparql_patterns
134
+ self.simple_method_names.inject("") {|outstring,item| outstring += "?instance <#{item}> ?#{item}. "}
135
+ end
136
+
137
+ #Converts the simple method names list into a string of SPARQL variables
138
+ def subClass.attributes_to_sparql_vars
139
+ "?instance ?" + self.simple_method_names.join(" ?")
140
+ end
141
+
142
+
143
+ ######################################
144
+ ######### SPARQL Find Methods ########
145
+ ######################################
146
+
147
+ #Does a SPARQL select based on simple options and instantiates the Class Instances From the Returning XML
148
+ def subClass.find(unique_uri_or_length, args={})
149
+ if unique_uri_or_length.class != Symbol
150
+ begin
151
+ puts "SELECT #{self.attributes_to_sparql_vars.gsub("?instance","")} WHERE { #{self.attributes_to_sparql_patterns.gsub("?instance",'<' + unique_uri_or_length + '>')}}"
152
+ graph_object = self.new(ResultParser.tableize(self.connection.find_by_sparql("SELECT #{self.attributes_to_sparql_vars.gsub("?instance","")} WHERE { #{self.attributes_to_sparql_patterns.gsub("?instance",'<' + unique_uri_or_length + '>')}}")).first)
153
+ graph_object.instance = unique_uri_or_length
154
+ return graph_object
155
+ rescue
156
+ return nil
157
+ end
158
+ elsif args.has_key?(:sparql) #Submit Pure Sparql without Object Creation (Returns Hash)
159
+ (ResultParser.tableize(self.connection.find_by_sparql(:sparql)))
160
+ elsif args.has_key?(:simple_conditional) #Returns objects that match the simple_condition, if specified, and apply the length operator via the send method
161
+ (ResultParser.tableize(self.connection.find_by_sparql("SELECT #{self.attributes_to_sparql_vars} WHERE {?instance rdf:type <#{self.rdf_class}> . #{args[:simple_conditional]} OPTIONAL {#{self.attributes_to_sparql_patterns}} . }")).collect {|table| self.new(table)}).send(unique_uri_or_length)
162
+ else
163
+ (ResultParser.tableize(self.connection.find_by_sparql("SELECT #{self.attributes_to_sparql_vars} WHERE {?instance rdf:type <#{self.rdf_class}> . OPTIONAL {#{self.attributes_to_sparql_patterns}} . }")).collect {|table| self.new(table)}).send(unique_uri_or_length)
164
+ end
165
+ end
166
+
167
+ def subClass.uniques(args={})
168
+ uniques = []
169
+ generals = self.find(:all, args)
170
+ generals.each {|g| uniques << g unless uniques.find {|u| u.instance == g.instance}}
171
+ uniques
172
+ end
173
+
174
+ #########################################
175
+ ########## Class Admin Methods ##########
176
+ #########################################
177
+
178
+
179
+ #########################################
180
+ ######## Class Initializer Calls ########
181
+ #########################################
182
+ subClass.set_attributes
183
+ subClass.set_attribute_method_names
184
+ end
185
+
186
+ #Class methods for ActiveSesame::Base
187
+ #These will not be inherited by sub classes
188
+ class << self
189
+ end
190
+
191
+ ######################################
192
+ ########## Instance Methods ##########
193
+ ######################################
194
+
195
+ def initialize(attributes_table={})
196
+ @attribute_table = attributes_table
197
+ @attribute_table.each {|key,value| self.send(key.to_s + "=", ActiveSesame::Support.uncode_whitespace(value)) }
198
+ end
199
+
200
+ def add_transaction_triple(s,p,o)
201
+ self.transaction_triples = self.transaction_triples + ActiveSesame::TransactionBuilder.build_triple(s,p,o)
202
+ end
203
+
204
+ def save
205
+ if self.class.validate(self)
206
+ self.build_triples
207
+ self.before_save
208
+ self.class.group_save(self.transaction_triples)
209
+ self.after_save
210
+ return true
211
+ else
212
+ self.after_save
213
+ return false
214
+ end
215
+ end
216
+
217
+ def build_triples
218
+ self.transaction_triples = ActiveSesame::TransactionBuilder.object_to_triples(self)
219
+ end
220
+
221
+ def before_save
222
+ end
223
+
224
+ def after_save
225
+ self.class.complex_method_names.each do |method|
226
+ values = self.send(method.to_s.pluralize + "_for_" + self.class.rdf_class.downcase)
227
+ values.to_a
228
+ if self.send(method.to_s.pluralize + "_for_" + self.class.rdf_class.downcase)
229
+ values.each {|value| self.send("add_" + method.to_s.pluralize, value)}
230
+ end
231
+ end
232
+ end
233
+
234
+ end
235
+ end
@@ -0,0 +1,38 @@
1
+ module ActiveSesame::Behaviors
2
+
3
+ module Ontology
4
+
5
+ def self.mimic(klass, options={})
6
+ defaults = {:repository => ActiveSesame::Repository.new, :ontology_attribute => :name}
7
+ defaults.merge!(options)
8
+ klass.send(:include, self)
9
+ klass.repository = defaults[:repository]
10
+ klass.ontology_attribute = defaults[:ontology_attribute]
11
+ return klass
12
+ end
13
+
14
+ def self.included(klass)
15
+ class << klass
16
+ attr_accessor :ontology_attribute, :repository
17
+ end
18
+
19
+ klass.ontology_attribute = :name
20
+ klass.repository = ActiveSesame::Repository.new
21
+ klass.class_eval do
22
+ def self.set_ontology_attribute(value,&block)
23
+ block_given? ? attribute_value = yield(value) : attribute_value = value
24
+ self.ontology_attribute = value.to_sym
25
+ end
26
+
27
+ def self.set_repository(repository)
28
+ self.repository = repository
29
+ end
30
+ end
31
+ end
32
+
33
+ def ontology
34
+ @ontology ||= ActiveSesame::Ontology::Term.new(self.send(self.class.ontology_attribute), self.class.repository)
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,25 @@
1
+ require 'active_support'
2
+ require 'active_sesame'
3
+ class Study < ActiveSesame::Base
4
+ end
5
+
6
+ @study_hash = {}
7
+ Study.simple_method_names.each {|key| @study_hash[key] = "" }
8
+ @study_hash[:patientSex] = "M"
9
+ @study_hash[:procedureCode] = "A CT of the Head"
10
+ @study_hash[:aquiringModality] = "CT"
11
+ @study_hash[:patientAge] = "015Y"
12
+ @study_hash[:patientHistory] = "Cronic Headaches"
13
+ @study_hash[:accessionNumber] = "0523432"
14
+ @study_hash[:studyDateTime] = "2007-08-11 13:02"
15
+ @study_hash[:bodyPartExamined] = "Head"
16
+ @study_hash[:patientID] = "101"
17
+ @study_hash[:reasonFor] = "Cronic Headaches"
18
+ @study_hash[:submittedBy] = "mwarnock"
19
+ @study_hash[:patientName] = "John Doe"
20
+ @study_hash[:uid] = "1.2.34.53534.32342342.9885"
21
+ @study_hash[:instance] = Study.base_uri_location + @study_hash[:uid].gsub(".","_")
22
+ @study = Study.new(@study_hash)
23
+ @study.save
24
+
25
+ puts Study.find(:all).inspect
@@ -0,0 +1,15 @@
1
+ module ActiveSesame
2
+ module MonkeyPatches
3
+ Array.class_eval do
4
+ def all
5
+ self
6
+ end
7
+ end
8
+
9
+ Hash.class_eval do
10
+ def to_triple
11
+ ActiveSesame::Triple.new(self)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,93 @@
1
+ module ActiveSesame::Ontology
2
+ class Term
3
+
4
+ class << self
5
+ attr_accessor :repository
6
+ end
7
+
8
+ attr_reader :relationships, :relationship_map, :term_type, :term, :unsaved_triples
9
+ extend ActiveSesame::Support
10
+
11
+ def method_missing(method, *args, &block)
12
+ if @relationships.has_key?(method.to_s)
13
+ if @relationships[method].class == Term
14
+ @relationships[method]
15
+ else
16
+ @relationships[method] = Term.new(@relationships[method.to_s])
17
+ end
18
+ else
19
+ super(method, *args, &block)
20
+ end
21
+ end
22
+
23
+ def initialize(ontoterm, repo = ActiveSesame::Repository.new)
24
+ self.class.repository = repo
25
+ @term = ontoterm
26
+ @unsaved_triples = []
27
+ set_relationships
28
+ end
29
+
30
+ def reset
31
+ @relationships = {}
32
+ @relationship_map = nil
33
+ set_relationships
34
+ true
35
+ end
36
+
37
+ def to_triples
38
+ self.relationship_map.collect do |po_hash|
39
+ ActiveSesame::Triple.new({:subject => self.term, :predicate => po_hash["predicate"], :object => po_hash["object"]})
40
+ end
41
+ end
42
+
43
+ def add_relationship(triple)
44
+ triple[:subject] = self.term unless triple.class == ActiveSesame::Triple and not (triple.has_key?[:subject] or triple.has_key?["subject"])
45
+ triple = triple.to_triple
46
+ key = self.class.method_from_uri(triple.predicate, "base" => self.class.repository.base_uri) #This is using rdf constants
47
+ if not self.relationships.has_key?(key)
48
+ self.relationships[key] = triple.object
49
+ elsif self.relationships[key].class != Array
50
+ self.relationships[key] = [self.relationships[key], triple.object]
51
+ else
52
+ self.relationships[key] << triple.object
53
+ end
54
+ end
55
+
56
+ def add_triple(triple)
57
+ expanded_triple = self.class.expand_triple(triple, self.class.repository.prefixes.merge({"base" => self.class.repository.base_uri}))
58
+ self.unsaved_triples << expanded_triple
59
+ self.add_relationship(expanded_triple)
60
+ end
61
+
62
+
63
+ def save
64
+ success = self.class.repository.group_save(self.transactions)
65
+ if success
66
+ @unsaved_triples = []
67
+ success
68
+ else
69
+ success
70
+ end
71
+ end
72
+
73
+ def transactions
74
+ ActiveSesame::TransactionBuilder.build_triples(self.unsaved_triples)
75
+ end
76
+
77
+ private
78
+ def set_relationships
79
+ @term = self.class.expand_term(@term, self.class.repository.prefixes.merge({"base" => self.class.repository.base_uri}))
80
+ if self.class.is_uri?(@term)
81
+ @term_type = "uri"
82
+ @relationship_map ||= self.class.repository.find("SELECT ?predicate ?object WHERE { <#{@term}> ?predicate ?object }")
83
+ @relationships = {}
84
+ self.relationship_map.each {|map| self.add_relationship(map) }
85
+ else
86
+ @term_type = "literal"
87
+ end
88
+ end
89
+
90
+
91
+ end
92
+
93
+ end