harukizaemon-drupal_fu 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ == 1.0.0 released 2009-01-12
2
+
3
+ * Add some very basic RDOC and packaged up as a gem.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Cogent Consulting, Pty. Ltd.
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.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = Drupal Fu
2
+
3
+ Drupal Fu is a Ruby on Rails plugin that helps with integrating Rails applications with Drupal.
4
+
5
+ == Installation
6
+
7
+ You have two choices for installation. The first uses a gem (recommended):
8
+
9
+ config.gem "harukizaemon-drupal_fu", :lib => "drupal_fu", :source => "http://gems.github.com"
10
+
11
+ Or you can use the Rails plugin
12
+
13
+ $ ruby script/plugin install git://github.com/harukizaemon/drupal_fu.git
14
+
15
+ === License
16
+
17
+ This plugin is copyright 2009 by 2009 Cogent Consulting, Pty. Ltd. and is released under the MIT license.
data/drupal_fu.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "drupal_fu"
3
+ s.version = "1.0.0"
4
+ s.date = "2009-01-12"
5
+ s.summary = "Ruby on Rails Models and Helpers for integrating with Drupal."
6
+ s.email = "simon.harris@cogentconsulting.com.au"
7
+ s.homepage = "http://github.com/harukizaemon/drupal_fu"
8
+ s.description = "Ruby on Rails Models and Helpers for integrating with Drupal."
9
+ s.has_rdoc = true
10
+ s.authors = ["Simon Harris"]
11
+ s.files = ["CHANGELOG.rdoc",
12
+ "MIT-LICENSE",
13
+ "README.rdoc",
14
+ "drupal_fu.gemspec",
15
+ "lib/drupal/authmap.rb",
16
+ "lib/drupal/base.rb",
17
+ "lib/drupal/helper.rb",
18
+ "lib/drupal/menu_link.rb",
19
+ "lib/drupal/menu_router.rb",
20
+ "lib/drupal/profile_field.rb",
21
+ "lib/drupal/serialize.rb",
22
+ "lib/drupal/session.rb",
23
+ "lib/drupal/session_store.rb",
24
+ "lib/drupal/url_alias.rb",
25
+ "lib/drupal/user.rb",
26
+ "lib/drupal/variable.rb",
27
+ "lib/drupal_fu.rb",
28
+ "lib/tasks",
29
+ "lib/tasks/drupal.rake"]
30
+ s.rdoc_options = ["--main", "README.rdoc"]
31
+ s.extra_rdoc_files = ["CHANGELOG.rdoc", "README.rdoc"]
32
+ end
@@ -0,0 +1,6 @@
1
+ module Drupal
2
+ class Authmap < Base
3
+ set_table_name "authmap"
4
+ set_primary_key "aid"
5
+ end
6
+ end
@@ -0,0 +1,31 @@
1
+ module Drupal
2
+ # Base class for all Drupal-specific model classes. If your Rails and Drupal applications share a common database then
3
+ # you can use this class as is. If your Drupal database is seperate, you can do something along the lines of the
4
+ # following in environment.rb:
5
+ #
6
+ # Drupal::Base.establish_connection "drupal_#{RAILS_ENV}"
7
+ #
8
+ # And add the corresponding entries in database.yml; one for each environment.
9
+ class Base < ActiveRecord::Base
10
+ self.abstract_class = true
11
+
12
+ protected
13
+
14
+ # Convenience method for marking model attributes as serialized. Supports a Ruby-compatible subset of the PHP
15
+ # serialisation mechanism.
16
+ def self.serializes(*attr_names)
17
+ attr_names.each do |attr_name|
18
+ class_eval <<-EOS
19
+ def #{attr_name}
20
+ @unserialized_#{attr_name} ||= Drupal::Serialize.unserialize(super)
21
+ end
22
+
23
+ def #{attr_name}=(new_value)
24
+ @unserialized_#{attr_name} = new_value
25
+ super Drupal::Serialize.serialize(new_value)
26
+ end
27
+ EOS
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,46 @@
1
+ module Drupal
2
+ # Some useful helper methods for accessing various configuration items. Simply include this module in whichever
3
+ # controller(s) need the behaviour. For example:
4
+ #
5
+ # class ApplicationController < ActionController::Base
6
+ # include Drupal::Helper
7
+ # ...
8
+ # end
9
+ module Helper
10
+ def self.included(base)
11
+ base.send(:helper_method, :primary_links, :root_path, :login_path, :site_name, :site_slogan)
12
+ end
13
+
14
+ protected
15
+
16
+ def primary_links
17
+ @primary_links ||= menu_links('primary-links')
18
+ end
19
+
20
+ def root_path
21
+ "/"
22
+ end
23
+
24
+ def login_path
25
+ @login_path ||= Drupal::UrlAlias.url_for("/user/login")
26
+ end
27
+
28
+ def site_name
29
+ @site_name ||= Drupal::Variable.value_of("site_name")
30
+ end
31
+
32
+ def site_slogan
33
+ @site_slogan ||= Drupal::Variable.value_of("site_slogan")
34
+ end
35
+
36
+ private
37
+
38
+ def menu_links(name)
39
+ Drupal::MenuLink.find(:all,
40
+ :joins => :menu_router,
41
+ :conditions => ["menu_name = ? AND hidden = 0 AND #{Drupal::MenuRouter.table_name}.access_callback <> 'user_is_anonymous'", name],
42
+ :order => "weight",
43
+ :readonly => true)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ module Drupal
2
+ class MenuLink < Base
3
+ set_primary_key "mlid"
4
+ serializes "options"
5
+ belongs_to :menu_router, :foreign_key => "router_path", :class_name => "Drupal::MenuRouter"
6
+
7
+ def title
8
+ link_title
9
+ end
10
+
11
+ def path
12
+ @path ||= Drupal::UrlAlias.url_for(link_path)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module Drupal
2
+ class MenuRouter < Base
3
+ set_table_name "menu_router"
4
+ set_primary_key "path"
5
+ self.inheritance_column = nil
6
+ serializes "access_arguments", "page_arguments", "title_arguments", "load_functions", "to_arg_functions"
7
+ has_many :menu_links, :foreign_key => "router_path", :class_name => "Drupal::MenuLink"
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ module Drupal
2
+ class ProfileField < Base
3
+ set_primary_key "fid"
4
+ self.inheritance_column = nil
5
+ has_and_belongs_to_many :users, :class_name => "Drupal::User", :join_table => "profile_values", :foreign_key => "fid", :association_foreign_key => "uid"
6
+
7
+ def value
8
+ @unserialized_value ||= case self[:type]
9
+ when "checkbox" then super != "0"
10
+ when "url" then URI.parse(super)
11
+ when "date"
12
+ hash = Serialize.unserialize(super)
13
+ Date.new(hash["year"].to_i, hash["month"].to_i, hash["day"].to_i)
14
+ when "list" then super.split(/[,\n\r]/).map(&:strip)
15
+ else super
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,189 @@
1
+ module Drupal
2
+ # Implements a Ruby-compatible subset of the PHP serialisation mechanism. This is often used for storing structured
3
+ # data in text database columns.
4
+ module Serialize
5
+ # Serialises a value. For example:
6
+ #
7
+ # Drupal::Serialize.serialize("Hello, World!") # => "s:13:\"Hello, World!\";"
8
+ def self.serialize(var, assoc = false)
9
+ s = ''
10
+ case var
11
+ when Array
12
+ s << "a:#{var.size}:{"
13
+ if assoc and var.first.is_a?(Array) and var.first.size == 2
14
+ var.each { |k,v|
15
+ s << self.serialize(k) << self.serialize(v)
16
+ }
17
+ else
18
+ var.each_with_index { |v,i|
19
+ s << "i:#{i};#{self.serialize(v)}"
20
+ }
21
+ end
22
+
23
+ s << '}'
24
+
25
+ when Hash
26
+ s << "a:#{var.size}:{"
27
+ var.each do |k,v|
28
+ s << "#{self.serialize(k)}#{self.serialize(v)}"
29
+ end
30
+ s << '}'
31
+
32
+ when Struct
33
+ # encode as Object with same name
34
+ s << "O:#{var.class.to_s.length}:\"#{var.class.to_s.downcase}\":#{var.members.length}:{"
35
+ var.members.each do |member|
36
+ s << "#{self.serialize(member)}#{self.serialize(var[member])}"
37
+ end
38
+ s << '}'
39
+
40
+ when String
41
+ s << "s:#{var.length}:\"#{var}\";"
42
+
43
+ when Fixnum # PHP doesn't have bignums
44
+ s << "i:#{var};"
45
+
46
+ when Float
47
+ s << "d:#{var};"
48
+
49
+ when NilClass
50
+ s << 'N;'
51
+
52
+ when FalseClass, TrueClass
53
+ s << "b:#{var ? 1 :0};"
54
+
55
+ else
56
+ if var.respond_to?(:to_assoc)
57
+ v = var.to_assoc
58
+ # encode as Object with same name
59
+ s << "O:#{var.class.to_s.length}:\"#{var.class.to_s.downcase}\":#{v.length}:{"
60
+ v.each do |k,v|
61
+ s << "#{self.serialize(k.to_s)}#{self.serialize(v)}"
62
+ end
63
+ s << '}'
64
+ else
65
+ raise TypeError, "Unable to serialize type #{var.class}"
66
+ end
67
+ end
68
+
69
+ s
70
+ end
71
+
72
+ # Unserialises a value. For example:
73
+ #
74
+ # Drupal::Serialize.unserialize("s:13:\"Hello, World!\";") # "Hello, World!"
75
+ def self.unserialize(string, classmap = nil, assoc = false)
76
+ string = StringIO.new(string)
77
+ def string.read_until(char)
78
+ val = ''
79
+ while (c = self.read(1)) != char
80
+ val << c
81
+ end
82
+ val
83
+ end
84
+
85
+ classmap ||= Hash.new
86
+
87
+ _unserialize(string, classmap, assoc)
88
+ end
89
+
90
+ private
91
+
92
+ def self._unserialize(string, classmap, assoc)
93
+ val = nil
94
+ # determine a type
95
+ type = string.read(2)[0,1]
96
+ case type
97
+ when 'a' # associative array, a:length:{[index][value]...}
98
+ count = string.read_until('{').to_i
99
+ val = vals = Array.new
100
+ count.times do |i|
101
+ vals << [_unserialize(string, classmap, assoc), _unserialize(string, classmap, assoc)]
102
+ end
103
+ string.read(1) # skip the ending }
104
+
105
+ unless assoc
106
+ # now, we have an associative array, let's clean it up a bit...
107
+ # arrays have all numeric indexes, in order; otherwise we assume a hash
108
+ array = true
109
+ i = 0
110
+ vals.each do |key,value|
111
+ if key != i # wrong index -> assume hash
112
+ array = false
113
+ break
114
+ end
115
+ i += 1
116
+ end
117
+
118
+ if array
119
+ vals.collect! do |key,value|
120
+ value
121
+ end
122
+ else
123
+ val = Hash.new
124
+ vals.each do |key,value|
125
+ val[key] = value
126
+ end
127
+ end
128
+ end
129
+
130
+ when 'O' # object, O:length:"class":length:{[attribute][value]...}
131
+ # class name (lowercase in PHP, grr)
132
+ len = string.read_until(':').to_i + 3 # quotes, seperator
133
+ klass = string.read(len)[1...-2].capitalize.intern # read it, kill useless quotes
134
+
135
+ # read the attributes
136
+ attrs = []
137
+ len = string.read_until('{').to_i
138
+
139
+ len.times do
140
+ attr = (_unserialize(string, classmap, assoc))
141
+ attrs << [attr.intern, (attr << '=').intern, _unserialize(string, classmap, assoc)]
142
+ end
143
+ string.read(1)
144
+
145
+ val = nil
146
+ # See if we need to map to a particular object
147
+ if classmap.has_key?(klass)
148
+ val = classmap[klass].new
149
+ elsif Struct.const_defined?(klass) # Nope; see if there's a Struct
150
+ classmap[klass] = val = Struct.const_get(klass)
151
+ val = val.new
152
+ else # Nope; see if there's a Constant
153
+ begin
154
+ classmap[klass] = val = Module.const_get(klass)
155
+
156
+ val = val.new
157
+ rescue NameError # Nope; make a new Struct
158
+ classmap[klass] = val = Struct.new(klass.to_s, *attrs.collect { |v| v[0].to_s })
159
+ end
160
+ end
161
+
162
+ attrs.each do |attr,attrassign,v|
163
+ val.__send__(attrassign, v)
164
+ end
165
+
166
+ when 's' # string, s:length:"data";
167
+ len = string.read_until(':').to_i + 3 # quotes, separator
168
+ val = string.read(len)[1...-2] # read it, kill useless quotes
169
+
170
+ when 'i' # integer, i:123
171
+ val = string.read_until(';').to_i
172
+
173
+ when 'd' # double (float), d:1.23
174
+ val = string.read_until(';').to_f
175
+
176
+ when 'N' # NULL, N;
177
+ val = nil
178
+
179
+ when 'b' # bool, b:0 or 1
180
+ val = (string.read(2)[0] == ?1 ? true : false)
181
+
182
+ else
183
+ raise TypeError, "Unable to unserialize type '#{type}'"
184
+ end
185
+
186
+ val
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,35 @@
1
+ module Drupal
2
+ class Session < Base
3
+ set_primary_key "sid"
4
+ belongs_to :user, :foreign_key => "uid", :class_name => "Drupal::User"
5
+
6
+ def self.authenticate(sid)
7
+ find(:first, :conditions => ["#{table_name}.sid = ? AND #{User.table_name}.status = 1", sid], :include => :user)
8
+ end
9
+
10
+ def session
11
+ @unserialized_session ||= decode(super || "")
12
+ end
13
+
14
+ def session=(new_value)
15
+ @unserialized_data = new_value
16
+ super encode(new_value)
17
+ end
18
+
19
+ private
20
+
21
+ def encode(data)
22
+ result = ""
23
+ data.each { |key, value| result << key << "|" << Drupal::Serialize.serialize(value) }
24
+ result
25
+ end
26
+
27
+ def decode(data)
28
+ result = {}
29
+ vars = data.split(/([a-zA-Z0-9]+)\|/)
30
+ vars.shift
31
+ vars.each_slice(2) { |pair| result[pair.first] = Drupal::Serialize.unserialize(pair.last) }
32
+ result
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,65 @@
1
+ module Drupal
2
+ class SessionStore
3
+ def self.stub(login)
4
+ self.class_eval <<-EOS
5
+ def initialize_with_stubbing(session, options = {})
6
+ user = Drupal::User.find_or_create_by_name("#{login}")
7
+ user.update_attributes!(:status => 1)
8
+ Drupal::Session.find_or_create_by_sid_and_uid(session.session_id, user.uid)
9
+ initialize_without_stubbing(session, options)
10
+ end
11
+ alias_method_chain :initialize, :stubbing
12
+ EOS
13
+
14
+ Digest::MD5.hexdigest(login)
15
+ end
16
+
17
+ def initialize(session, options = {})
18
+ @session = Drupal::Session.authenticate(session.session_id)
19
+ raise CGI::Session::NoSession, "uninitialized session" if @session.nil?
20
+ end
21
+
22
+ # Restore session data from the record.
23
+ def restore
24
+ @data = decode(@session.session)
25
+ end
26
+
27
+ # Wait until close to write the session data.
28
+ def update; end
29
+
30
+ # Update the database.
31
+ def close
32
+ now = Time.now.to_i
33
+ @session.timestamp = now
34
+ @session.session = encode(@data) if defined?(@data)
35
+ @session.save!
36
+ @session.user.access = now
37
+ @session.user.save!
38
+ @session = nil
39
+ @data = nil
40
+ end
41
+
42
+ # This is handled by Drupal.
43
+ def delete
44
+ @session = nil
45
+ @data = nil
46
+ end
47
+
48
+ private
49
+
50
+ def encode(data)
51
+ data = data.dup
52
+ data.delete(:user)
53
+ data.delete("flash") if data["flash"].blank?
54
+ data
55
+ end
56
+
57
+ def decode(data)
58
+ data = data.dup
59
+ flash = data["flash"]
60
+ data["flash"] = ActionController::Flash::FlashHash.new.replace(flash) if flash
61
+ data[:user] = @session.user
62
+ data
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,14 @@
1
+ module Drupal
2
+ class UrlAlias < Base
3
+ set_table_name "url_alias"
4
+ set_primary_key "pid"
5
+
6
+ def self.url_for(path, language = "")
7
+ if url_alias = self.find_by_src_and_language(path, language)
8
+ url_alias.dst
9
+ else
10
+ path
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+ module Drupal
2
+ class User < Base
3
+ set_primary_key "uid"
4
+
5
+ has_many :sessions, :foreign_key => "sid", :class_name => "Drupal::Session"
6
+ has_and_belongs_to_many :profile_fields, :class_name => "Drupal::ProfileField", :join_table => "profile_values", :foreign_key => "uid", :association_foreign_key => "fid"
7
+ has_many :openids, :foreign_key => "uid", :class_name => "Drupal::Authmap", :conditions => { :module => "openid" }
8
+ serializes "data"
9
+
10
+ # Authenticate a user given a name and password. For example:
11
+ #
12
+ # if user = Drupal::User.authenticate("bob", "flibble")
13
+ # # At this point, we have a valid user record
14
+ # else
15
+ # # Could be an invalid user/password combo or the user might be blocked
16
+ # end
17
+ def self.authenticate(name, password)
18
+ find_by_name_and_pass_and_status(name, Digest::MD5.hexdigest(password), 1)
19
+ end
20
+
21
+ # Returns true if the user is allowed to login.
22
+ def active?
23
+ status == 1
24
+ end
25
+
26
+ # Returns true if the user has been barred from logging in.
27
+ def blocked?
28
+ !active?
29
+ end
30
+
31
+ # Returns true if the user is the system administrator account.
32
+ def administrator?
33
+ uid == 1
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ module Drupal
2
+ class Variable < Base
3
+ set_table_name "variable"
4
+ set_primary_key "name"
5
+ serializes "value"
6
+
7
+ def self.value_of(name)
8
+ if variable = self.find_by_name(name)
9
+ variable.value
10
+ end
11
+ end
12
+ end
13
+ end
data/lib/drupal_fu.rb ADDED
@@ -0,0 +1 @@
1
+ # Do stuff
@@ -0,0 +1,37 @@
1
+ namespace :drupal do
2
+ namespace :db do
3
+ namespace :test do
4
+ desc "Empty the drupal test database"
5
+ task :purge => :environment do
6
+ abcs = ActiveRecord::Base.configurations
7
+ ActiveRecord::Base.clear_active_connections!
8
+ drop_database(abcs['drupal_test'])
9
+ create_database(abcs['drupal_test'])
10
+ end
11
+
12
+ desc "Prepare the drupal test database"
13
+ task :prepare => "drupal:db:test:purge" do
14
+ Drupal::Base.establish_connection(ActiveRecord::Base.configurations['drupal_test'])
15
+ ActiveRecord::Schema.verbose = false
16
+ Rake::Task["drupal:db:schema:load"].invoke
17
+ end
18
+ end
19
+
20
+ namespace :schema do
21
+ desc "Create a db/drupal_schema.rb file that can be portably used against any DB supported by AR"
22
+ task :dump => :environment do
23
+ require 'active_record/schema_dumper'
24
+ File.open(ENV['DRUPAL_SCHEMA'] || "db/drupal_schema.rb", "w") do |file|
25
+ ActiveRecord::SchemaDumper.dump(Drupal::Base.connection, file)
26
+ end
27
+ end
28
+
29
+ desc "Load a drupal_schema.rb file into the database"
30
+ task :load => :environment do
31
+ ActiveRecord::Base.connection = Drupal::Base.connection
32
+ load(ENV['DRUPAL_SCHEMA'] || "db/drupal_schema.rb")
33
+ ActiveRecord::Base.clear_active_connections!
34
+ end
35
+ end
36
+ end
37
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: harukizaemon-drupal_fu
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Simon Harris
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-12 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Ruby on Rails Models and Helpers for integrating with Drupal.
17
+ email: simon.harris@cogentconsulting.com.au
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - CHANGELOG.rdoc
24
+ - README.rdoc
25
+ files:
26
+ - CHANGELOG.rdoc
27
+ - MIT-LICENSE
28
+ - README.rdoc
29
+ - drupal_fu.gemspec
30
+ - lib/drupal/authmap.rb
31
+ - lib/drupal/base.rb
32
+ - lib/drupal/helper.rb
33
+ - lib/drupal/menu_link.rb
34
+ - lib/drupal/menu_router.rb
35
+ - lib/drupal/profile_field.rb
36
+ - lib/drupal/serialize.rb
37
+ - lib/drupal/session.rb
38
+ - lib/drupal/session_store.rb
39
+ - lib/drupal/url_alias.rb
40
+ - lib/drupal/user.rb
41
+ - lib/drupal/variable.rb
42
+ - lib/drupal_fu.rb
43
+ - lib/tasks
44
+ - lib/tasks/drupal.rake
45
+ has_rdoc: true
46
+ homepage: http://github.com/harukizaemon/drupal_fu
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --main
50
+ - README.rdoc
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.2.0
69
+ signing_key:
70
+ specification_version: 2
71
+ summary: Ruby on Rails Models and Helpers for integrating with Drupal.
72
+ test_files: []
73
+