engrel 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Matt Lightner
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,62 @@
1
+ = **ENG**lish **REL**ational Framework
2
+
3
+ *A simple and elegant way to specify relations without explicitly making a table for each one.*
4
+
5
+ *Modify or delete this text in the editor above.*
6
+
7
+ WMD's context-sensitive commands pack a lot of power into a simple user interface. Here are some advanced features to try:
8
+
9
+ == Why use English/Sentences instead of Join Tables?
10
+
11
+ In a way, we are using join tables--but just one instead of dozens of hundreds. Normal join tables serve one single purpose--to connect A to B under circumstance C. Like to link all of the users who were tagged in a specific photo ID. But if you step back, all that join tables really do is link one object to another with a little bit of context. Engrel puts the context into the join table and voila, one join table can link any two objects **and** provide (often even more) useful context than a full join table. No really.
12
+
13
+ == Prepositional Phrases
14
+
15
+ Sounds like something only a linguistics professor would care about, but in reality, you use them all the time and they're very helpful in describing relations. For instance, taking an example from Facebook:
16
+
17
+ I was tagged in photo ID 23982930 (technically there's already a preposition there, but watch now)
18
+ I was tagged in photo ID 23982930 by user ID 850932
19
+
20
+ More info, right? And more data is always better, we think.
21
+
22
+
23
+ == Console Usage
24
+
25
+ irb(main):022:0> s = Engrel::Sentence.claim(User["00002394802384"], :likes, Page["overwerk"])
26
+ => #<Engrel::Sentence id: 1, subject_id: 00002394802384, subject_type: "User", direct_object_id: 133241766707287, direct_object_type: "Page", verb: "likes", data: nil, created_at: "2010-11-18 18:41:27", updated_at: "2010-11-18 18:41:27">
27
+
28
+ irb(main):024:0> s = Engrel::Sentence.claim(User["00002394802384"], :likes, Page["overwerk"])
29
+ => #<Engrel::Sentence id: 1, subject_id: 00002394802384, subject_type: "User", direct_object_id: 133241766707287, direct_object_type: "Page", verb: "likes", data: nil, created_at: "2010-11-18 18:41:27", updated_at: "2010-11-18 18:41:27">
30
+
31
+ irb(main):025:0> s.prep(:via, User["00002394804563"])
32
+ => #<Engrel::PrepositionalPhrase id: 2, parent_id: 1, parent_type: "Engrel::Sentence", preposition: "via", modifier: nil, indirect_object_id: 00002394804563, indirect_object_type: "User", created_at: "2010-11-18 20:15:39", updated_at: "2010-11-18 20:15:39", started_at: nil, ended_at: nil>
33
+
34
+ irb(main):026:0> pp s
35
+ => #<Engrel::Sentence id: 1, subject_id: 00002394802384, subject_type: "User", direct_object_id: 133241766707287, direct_object_type: "Page", verb: "likes", data: nil, created_at: "2010-11-18 18:41:27", updated_at: "2010-11-18 18:41:27">
36
+
37
+ irb(main):027:0> pp s.prepositional_phrases
38
+ => [#<Engrel::PrepositionalPhrase id: 2, parent_id: 1, parent_type: "Engrel::Sentence", preposition: "via", modifier: nil, indirect_object_id: 00002394804563, indirect_object_type: "User", created_at: "2010-11-18 20:15:39", updated_at: "2010-11-18 20:15:39", started_at: nil, ended_at: nil>]
39
+
40
+ irb(main):028:0> pp s.to_sentence
41
+ => "User[Matt Lightner#00002394802384] likes Page[OVERWERK#133241766707287] via User[Some Friend#00002394804563 indirect_object])
42
+
43
+
44
+ == Use with FBGraph
45
+
46
+
47
+ This was originally designed to solve a problem I ran into while trying to persist Facebook Graph data, and works well with the fbgraph (not fb_graph) library. I recommend you check that out too!
48
+
49
+ == Contributing to engrel
50
+
51
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
52
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
53
+ * Fork the project
54
+ * Start a feature/bugfix branch
55
+ * Commit and push until you are happy with your contribution
56
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
57
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
58
+
59
+ == Copyright
60
+
61
+ Copyright (c) 2010 Matt Lightner. See LICENSE.txt for
62
+ further details.
@@ -0,0 +1,43 @@
1
+ require 'active_record'
2
+ require 'enumerated_attribute'
3
+ require 'engrel/sentence'
4
+ require 'engrel/prepositional_phrase'
5
+ require 'engrel/mixin'
6
+
7
+ # Helper methods that make creating new sentences a joy!
8
+ module Engrel
9
+ module Helpers
10
+
11
+ # Creates a new relation from scratch--that is, without an implicit subject. Takes arguments in the order they would be written in
12
+ # an anglish sentence.
13
+ #
14
+ # @param [Object] an object, usually an actor.
15
+ # @param [Symbol] a verb from the vast pre-approved list that decsribes this relation.
16
+ # @param [Object] the direct object in this
17
+ # @returns [Sentence] The new Sentence object created to represent this relation.
18
+ def sentence(*args, &block)
19
+ Engrel::Sentence.claim(*args, &block)
20
+ end
21
+ alias :fact :sentence
22
+ alias :claim :sentence
23
+
24
+ module AciveRecordInstanceMethods
25
+ # Helper method that gets included into AR::Base that allows any model object to specify a relationship between it and any other
26
+ # object (the direct object (they're both polymorphic, of course).
27
+ #
28
+ # @param [Symbol] The downcased, underscored word representing the transitive verb i.e. (:is_friends_with)
29
+ # @param [Object] The direct object that is the second receiver for the trasitive verb above.
30
+ # @returns [Sentence] The new Sentence object created to represent this relation.
31
+ def fact(verb, direct_object, &block)
32
+ Engrel::Sentence.claim(self, verb, direct_object, &block)
33
+ end
34
+ alias :claim :fact
35
+ alias :sentence :claim
36
+ end
37
+
38
+ end
39
+ end
40
+
41
+
42
+ ActiveRecord::Base.send(:include, ::Engrel::Helpers::AciveRecordInstanceMethods) if (defined?(ActiveRecord::Base) rescue false)
43
+ include ::Engrel::Helpers
@@ -0,0 +1,34 @@
1
+ require 'active_support'
2
+
3
+ module Engrel
4
+ module Mixin
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ # Who knows--maybe I'll think of something to put here someday.
9
+ end
10
+
11
+ module InstanceMethods
12
+
13
+ # This is very specific to Facebook--it stores a reference to the object through whose access token the intermediate object was initially fetched.
14
+ def set_fetcher!(newfetcher = nil)
15
+ write_attribute(:fetcher_id, newfetcher[:id])
16
+ write_attribute(:fetcher_type, newfetcher.class.to_s)
17
+ save(:validate => false)
18
+ reload
19
+ fetcher
20
+ end
21
+
22
+ # Make sure we can make an object before we go trying to save the "association".
23
+ def instantiate_object!(key)
24
+ key = key.to_sym
25
+ id_key, type_key = "#{key}_id".to_sym, "#{key}_type".to_sym
26
+ return true if !self[key].blank? && !(self[key][:id].blank? rescue true)
27
+ class_name = self[type_key] || (self.send(key).class.to_s rescue "Page")
28
+ raise "Could not determine class name for #{key} (#{self.to_s})" if class_name.blank?
29
+ newid = self[id_key] || (self[key][:id] rescue nil)
30
+ class_name.constantize.spec(newid) rescue raise("Unable to instantiate #{class_name} object with ID #{newid || '[unavailable]'}")
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,83 @@
1
+ require 'engrel/mixin'
2
+
3
+ class Engrel::PrepositionalPhrase < ActiveRecord::Base
4
+ include Engrel::Mixin
5
+
6
+ # This whole top declaration will need changing if you're not using AR.
7
+ set_table_name "engrel_prepositional_phrases"
8
+
9
+ # A prepositional phrase, which answers the questions: how?, which one?, when? with whom? by whom? etc.
10
+ # http://www.chompchomp.com/terms/prepositionalphrase.htm
11
+ belongs_to :indirect_object, :polymorphic => true
12
+
13
+ # The sentence that owns us.
14
+ belongs_to :sentence, :class_name => "::Engrel::Sentence"
15
+
16
+ enum_attr :preposition, %w( ^about at_time on_date since beginning beginning_at before and as_well_as in_addition_to along_with together_with in_conjunction_with at_time on_date before prior_to after following since beginning beginning_at dring while at_the_sae_time_as about on in_reference_to concerning regarding in inside within inside_of included_in as_part_of via through by_way_of from by at located_at
17
+ with_location at_venue at_place and as_well_as in_addition_to along_with together_with in_conjunction_with ) do
18
+ at_time? %w( at_time on_date )
19
+ before? %w( before prior_to )
20
+ after? %w( after following )
21
+ since? %w( since beginning beginning_at )
22
+ during? %w( dring while at_the_sae_time_as )
23
+ about? %w( about on in_reference_to concerning regarding )
24
+ in? %w( in inside within inside_of included_in as_part_of )
25
+ via? %w( via through by_way_of from by )
26
+ at? %w( at located_at with_location at_venue at_place )
27
+ and? %w( and as_well_as in_addition_to along_with together_with in_conjunction_with )
28
+
29
+ references_time? { at_time? || before? || after? || during? || since? }
30
+ references_object? { in? || via? || about? }
31
+ references_location? { at? || via? } # Yes via is both?
32
+ end
33
+
34
+ alias :ind :indirect_object
35
+
36
+ before_save do
37
+ instantiate_object!(:indirect_object) unless !indirect_object.blank?
38
+ end
39
+
40
+ def has_indirect_object?
41
+ (self.indirect_object.present? && self.indirect_object[:id].present?) rescue false
42
+ end
43
+
44
+
45
+
46
+ #### Time Helpers! ####
47
+
48
+ def started_at
49
+ (references_time? && has_indirect_object?) && (ind.started_time rescue nil || ind.started_at rescue nil || ind.created_time rescue nil)
50
+ end
51
+
52
+ def started?; started_at.present?; end
53
+ alias :starts_at :started_at
54
+ alias :starts? :started?
55
+
56
+ def ended_at
57
+ (references_time? && has_indirect_object?) && (ind.ended_time rescue nil || ind.ended_at rescue nil || ind.created_time rescue nil)
58
+ end
59
+
60
+ def ended?; ended_at.present?; end
61
+ alias :ends_at :ended_at
62
+ alias :ends? :ended?
63
+
64
+ def now
65
+ @now ||= Time.now
66
+ end
67
+
68
+ def active?
69
+ (started? && !ended?) rescue nil
70
+ end
71
+ alias :ongoing? :active?
72
+
73
+ # Returning anything here is misleading. Maybe nil?
74
+ def ended?
75
+ (started_at < now && ended_at > now) rescue nil
76
+ end
77
+ alias :over? :ended?
78
+
79
+ def started?
80
+ (started_at < now) rescue nil
81
+ end
82
+
83
+ end
@@ -0,0 +1,132 @@
1
+ require 'engrel/mixin'
2
+ require 'engrel/prepositional_phrase'
3
+
4
+ class Engrel::Sentence < ActiveRecord::Base
5
+ # This is the main backbone of Engrel. A sentence is just a has and belongs to many relation with a verb attached that tells you the nature of the relationship.
6
+ # Prepositional phrases are optional and can make relationships ternary and more specific. A sentence can have as many prepositional phrases as is appropriate.
7
+
8
+ include Engrel::Mixin
9
+
10
+ # NOTE: TO non-AR users--this whole top declaration will need changing if you're not using AR.
11
+
12
+ # Set the table name so as not to clash with other tables.
13
+ set_table_name "engrel_sentences"
14
+
15
+ # Usually a user, since they're the "actors" in most systems. The "Who" of the sentence.
16
+ belongs_to :subject, :polymorphic => true
17
+
18
+ # The thing we're being related with. The "What" of the sentence, and the recipieit of theeffect of the transitive verb.
19
+ # http://www.chompchomp.com/terms/directobject.htm
20
+ belongs_to :direct_object, :polymorphic => true
21
+
22
+ # Prepositions are stored as children. Each has a preposition and an object (i.e. "beside the chair")
23
+ has_many :prepositional_phrases, :uniq => true
24
+
25
+ # There's obviously the possibility that dynamic accessors could be defined to access these "indirect object" so you could say like sentence.well post if the ternary
26
+ # relation was "Bob posted about Mary on his wall", where the post is the indirect object, mary is the direct object, and Bob is the subject.
27
+ has_many :indirect_objects, :through => :prepositional_phrases
28
+
29
+ # The verb. Specifically a transitive verb (it needs two objects).
30
+ # commented_on: Something comments on a direct_object.
31
+ # likes: Something likes a direct_object object.
32
+ # manages: Something manages a page.
33
+ # is_friends_with: A user knows another user.
34
+ # dates: A user dates another user (acts like: knows)
35
+ # is_related_to: A user is related to another user.
36
+ # attended: A user attended an event.
37
+ # worked_for/works_for: User employed by organization.
38
+ # attended/attends: User attends a school.
39
+ # checked_in: A user checks in to a page (through a subject)
40
+ # posted: Something posts an object (photo/video/album/link)
41
+ # messaged: Someone messages someone else.
42
+ # wall_messaged: Something posts on something's wall (about a subject/tagged_in user)
43
+ # subscribes_to: Something subscribes to a feed.
44
+ # write_note: Something wrote a note (about a subject)
45
+ # is: A status message.
46
+ # hosts: Something hosts an event..
47
+ # is_invited_to: A user is invited to an event/group.
48
+ enum_attr :verb, %w(^is_friends_with commented_on likes belongs_to manages dates is_related_to attended
49
+ is_friends_with dates is_related_to worked_for was_employed_by works_for was_laid_off_from founded works_part_time_for attended is_an_avid_alumni teaches_at subscribes_to wall_messaged
50
+ commented_on checked_in tagged_in posted messaged is wrote_note is_invited_to belongs_to worked_for works_for attends attended is_invited_to religiously_attends tagged_in visited
51
+ appears_to_be_having_fun_in is_posing_generically_in attends attended is_invited_to does_not_want_to_attend disliked_the_crowd_at ) do
52
+
53
+ # When the link acts like "knows" relation
54
+ # Facebook-specific verbs
55
+ knows? %w( is_friends_with dates is_related_to )
56
+ job? %w( worked_for was_employed_by works_for was_laid_off_from founded works_part_time_for)
57
+ education? %w( attended is_an_avid_alumni teaches_at)
58
+ subscription? %w( subscribes_to wall_messaged commented_on checked_in tagged_in posted messaged is wrote_note is_invited_to )
59
+ membership? %w( belongs_to worked_for works_for attends attended is_invited_to religiously_attends )
60
+ tag? %w( tagged_in visited appears_to_be_having_fun_in is_posing_generically_in )
61
+ event? %w( attends attended is_invited_to does_not_want_to_attend disliked_the_crowd_at )
62
+ end
63
+
64
+
65
+ # How we make a new sentence while ensuring an existing one doesn't exist.
66
+ def self.claim(subject, verb, direct_object)
67
+ params = {:subject_type => subject.class.to_s, :subject_id => subject[:id], :direct_object_type => direct_object.class.to_s, :direct_object_id => direct_object[:id], :verb => verb.to_s}.stringify_keys
68
+ s = self.where(params).first
69
+ s = create(params) if s.blank?
70
+ s.reload
71
+ block_given? ? yield(s) : s
72
+ end
73
+
74
+ # This describes the relationship of the subject to the fact.
75
+ # You can determine your own meaning for these, but try to document your use as you see fit.
76
+ before_save do
77
+ instantiate_object!(:subject)
78
+ instantiate_object!(:direct_object)
79
+ end
80
+
81
+ def object_list
82
+ [ subject, direct_object ].concat(indirect_objects).compact
83
+ end
84
+
85
+ def has_subject?
86
+ (self.subject.present? && self.subject[:id].present?) rescue false
87
+ end
88
+
89
+ def has_direct_object?
90
+ (self.direct_object.present? && self.direct_object[:id].present?) rescue false
91
+ end
92
+
93
+ def verb_enums
94
+ self.enums(:verb)
95
+ end
96
+
97
+ def verb_label(element = nil)
98
+ element ||= self.verb
99
+ verb_enums.label(element.to_sym)
100
+ end
101
+
102
+ def only(*args)
103
+ self.prepositional_phrases.clear
104
+ prep(*args)
105
+ self
106
+ end
107
+
108
+ def prep(prep, indirect_object)
109
+ if self.prepositional_phrases.include?(preposition: prep, indirect_object_id: indirect_object.id, indirect_object_type: indirect_object.class.to_s)
110
+ warn "PREP ALREADY EXISTS!"
111
+ else
112
+ self.prepositional_phrases.create(preposition: prep, indirect_object: indirect_object)
113
+ end
114
+ self
115
+ end
116
+
117
+ def to_sentence_colored
118
+ sen = "#{subject_type.humanize}[#{subject.name rescue subject_id}\##{subject_id}]".green +
119
+ " #{verb_label.downcase} " + "#{direct_object_type.humanize}[#{direct_object.name rescue direct_object_id}\##{direct_object_id}]".cyan
120
+ sen += " " unless prepositional_phrases.blank? rescue true
121
+ preps = prepositional_phrases.collect { |p| "#{p.preposition.to_s.humanize.downcase} " + "#{p.indirect_object_type.humanize}[#{p.object.name rescue p.indirect_object_id}\##{p.indirect_object_id}]".yellow }.join(" ") rescue nil
122
+ sen << preps unless preps.blank?
123
+ sen += '.'
124
+ sen
125
+ end
126
+
127
+ # TODO: Properly strip ANSI color chars
128
+ def to_sentence
129
+ to_sentence_colored
130
+ end
131
+ end
132
+
@@ -0,0 +1,19 @@
1
+ require 'rails/generators/migration'
2
+
3
+ # Very simple--we're doing a straight copy of the migration.
4
+ class EngrelGenerator < Rails::Generators::Base
5
+ include Rails::Generators::Migration
6
+
7
+ def self.source_root
8
+ @_acts_as_engrelable_source_root ||= File.expand_path("../templates", __FILE__)
9
+ end
10
+
11
+ def self.next_migration_number(path)
12
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
13
+ end
14
+
15
+ def create_model_file
16
+ template "engrel.rb", "app/models/engrel.rb"
17
+ migration_template "create_engrel_tables.rb", "db/migrate/create_engrel_tables.rb"
18
+ end
19
+ end
@@ -0,0 +1,47 @@
1
+ class CreateEngrelTables < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :engrel_sentences, :force => true do |t|
4
+ t.column :subject_id, "BIGINT"
5
+ t.column :subject_type, :string
6
+
7
+ t.column :direct_object_id, "BIGINT"
8
+ t.column :direct_object_type, :string
9
+
10
+ t.enum :verb
11
+ t.string :direct_object_data
12
+
13
+ t.datetime :created_at
14
+ t.datetime :updated_at
15
+ end
16
+
17
+ add_index :engrel_sentences, :direct_object_id, :name => "direct_object_index"
18
+ add_index :engrel_sentences, :subject_id, :name => "subject_index"
19
+ add_index :engrel_sentences, :verb, :name => "verb_index"
20
+ change_column :engrel_sentences, :id, 'BIGINT NOT NULL AUTO_INCREMENT' # For big IDs like Facebook
21
+
22
+ create_table :engrel_prepositional_phrases, :force => true do |t|
23
+ t.references :sentence
24
+
25
+ t.enum :preposition
26
+ t.enum :modifier
27
+
28
+ t.column :indirect_object_id, "BIGINT"
29
+ t.column :indirect_object_type, :string
30
+
31
+ t.string :indirect_object_data
32
+
33
+ t.datetime :created_at
34
+ t.datetime :updated_at
35
+ end
36
+
37
+ add_index :engrel_prepositional_phrases, :indirect_object_id, :name => "indirect_object_index"
38
+ add_index :engrel_prepositional_phrases, :preposition, :name => "preposition_index"
39
+ change_column :engrel_prepositional_phrases, :id, 'BIGINT NOT NULL AUTO_INCREMENT'
40
+ end
41
+
42
+ def self.down
43
+ drop_table :engrel_sentences
44
+ drop_table :engrel_prepositional_phrases
45
+ end
46
+
47
+ end
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+
12
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ require 'engrel'
15
+
16
+ class Test::Unit::TestCase
17
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestEngrel < Test::Unit::TestCase
4
+ def test_something_for_real
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,204 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: engrel
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 10
8
+ - 0
9
+ version: 0.10.0
10
+ platform: ruby
11
+ authors:
12
+ - Matt Lightner
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-11-24 00:00:00 -06:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activerecord
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 3
29
+ - 0
30
+ - 0
31
+ version: 3.0.0
32
+ type: :runtime
33
+ prerelease: false
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: activesupport
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 3
44
+ - 0
45
+ - 0
46
+ version: 3.0.0
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: text-highlight
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :runtime
61
+ prerelease: false
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: enumerated_attribute
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ type: :runtime
74
+ prerelease: false
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: yard
78
+ requirement: &id005 !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ segments:
84
+ - 0
85
+ - 6
86
+ - 0
87
+ version: 0.6.0
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *id005
91
+ - !ruby/object:Gem::Dependency
92
+ name: bundler
93
+ requirement: &id006 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ~>
97
+ - !ruby/object:Gem::Version
98
+ segments:
99
+ - 1
100
+ - 0
101
+ - 0
102
+ version: 1.0.0
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: *id006
106
+ - !ruby/object:Gem::Dependency
107
+ name: jeweler
108
+ requirement: &id007 !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ~>
112
+ - !ruby/object:Gem::Version
113
+ segments:
114
+ - 1
115
+ - 5
116
+ - 1
117
+ version: 1.5.1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: *id007
121
+ - !ruby/object:Gem::Dependency
122
+ name: rcov
123
+ requirement: &id008 !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ segments:
129
+ - 0
130
+ version: "0"
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: *id008
134
+ - !ruby/object:Gem::Dependency
135
+ name: active_support
136
+ requirement: &id009 !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ">"
140
+ - !ruby/object:Gem::Version
141
+ segments:
142
+ - 3
143
+ - 0
144
+ - 0
145
+ version: 3.0.0
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: *id009
149
+ description: Allows for natural grammar to specify object relationships based on parts of speech.
150
+ email: mlightner@gmail.com
151
+ executables: []
152
+
153
+ extensions: []
154
+
155
+ extra_rdoc_files:
156
+ - LICENSE.txt
157
+ - README.rdoc
158
+ files:
159
+ - README.rdoc
160
+ - lib/engrel.rb
161
+ - lib/engrel/mixin.rb
162
+ - lib/engrel/prepositional_phrase.rb
163
+ - lib/engrel/sentence.rb
164
+ - lib/generators/engrel_generator.rb
165
+ - lib/generators/templates/create_engrel_tables.rb
166
+ - LICENSE.txt
167
+ - test/helper.rb
168
+ - test/test_engrel.rb
169
+ has_rdoc: true
170
+ homepage: http://engrel.com
171
+ licenses:
172
+ - MIT
173
+ post_install_message:
174
+ rdoc_options: []
175
+
176
+ require_paths:
177
+ - lib
178
+ required_ruby_version: !ruby/object:Gem::Requirement
179
+ none: false
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ hash: 3076847749877114109
184
+ segments:
185
+ - 0
186
+ version: "0"
187
+ required_rubygems_version: !ruby/object:Gem::Requirement
188
+ none: false
189
+ requirements:
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ segments:
193
+ - 0
194
+ version: "0"
195
+ requirements: []
196
+
197
+ rubyforge_project:
198
+ rubygems_version: 1.3.7
199
+ signing_key:
200
+ specification_version: 3
201
+ summary: A highly flexible entity relationship management system that requires only two tables and lots of clever.
202
+ test_files:
203
+ - test/helper.rb
204
+ - test/test_engrel.rb