glass-rails 0.0.1
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/.DS_Store +0 -0
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +172 -0
- data/Rakefile +1 -0
- data/glass-rails.gemspec +33 -0
- data/lib/.DS_Store +0 -0
- data/lib/generators/.DS_Store +0 -0
- data/lib/generators/glass.rb +22 -0
- data/lib/generators/glass/.DS_Store +0 -0
- data/lib/generators/glass/install/install_generator.rb +38 -0
- data/lib/generators/glass/install/templates/glass_timeline_item_migration.rb +21 -0
- data/lib/generators/glass/install/templates/google-oauth.yml +15 -0
- data/lib/generators/glass/install/templates/google_account.rb +28 -0
- data/lib/generators/glass/install/templates/initializer.rb +24 -0
- data/lib/generators/glass/install/templates/notifications_controller.rb +7 -0
- data/lib/generators/glass/model/model_generator.rb +19 -0
- data/lib/generators/glass/model/templates/model.rb +28 -0
- data/lib/generators/glass/templates/.DS_Store +0 -0
- data/lib/generators/glass/templates/templates/image_full.html.erb +9 -0
- data/lib/generators/glass/templates/templates/image_left_with_section_right.html.erb +8 -0
- data/lib/generators/glass/templates/templates/image_left_with_table_right.html.erb +11 -0
- data/lib/generators/glass/templates/templates/list.html.erb +7 -0
- data/lib/generators/glass/templates/templates/simple.html.erb +7 -0
- data/lib/generators/glass/templates/templates/table.html.erb +8 -0
- data/lib/generators/glass/templates/templates/two_column.html.erb +12 -0
- data/lib/generators/glass/templates/templates/two_column_with_emphasis_left.html.erb +14 -0
- data/lib/generators/glass/templates/templates_generator.rb +16 -0
- data/lib/glass-rails.rb +7 -0
- data/lib/glass.rb +24 -0
- data/lib/glass/.DS_Store +0 -0
- data/lib/glass/api_keys.rb +29 -0
- data/lib/glass/client.rb +95 -0
- data/lib/glass/engine.rb +5 -0
- data/lib/glass/menu_item.rb +33 -0
- data/lib/glass/rails/version.rb +5 -0
- data/lib/glass/subscription.rb +46 -0
- data/lib/glass/subscription_notification.rb +75 -0
- data/lib/glass/template.rb +45 -0
- data/lib/glass/timeline_item.rb +259 -0
- data/spec/models/glass/template_spec.rb +12 -0
- data/spec/models/glass/timeline_item_spec.rb +9 -0
- data/spec/spec_helper.rb +55 -0
- metadata +226 -0
data/.DS_Store
ADDED
Binary file
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Thirst Labs, Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
# Glass::Rails
|
2
|
+
|
3
|
+
A DSL for building Google Glass apps using Ruby on Rails.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'glass-rails'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install locally by running the following command:
|
16
|
+
|
17
|
+
$ gem install glass-rails
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### Setting up
|
22
|
+
|
23
|
+
We have a rails generator which will generate a
|
24
|
+
yaml file for your google api keys. The command for
|
25
|
+
the generator is:
|
26
|
+
|
27
|
+
rails g glass:install
|
28
|
+
|
29
|
+
This will generate a yaml file for your keys, an initializer for
|
30
|
+
setting up configuration details, and migrations for the appropriate
|
31
|
+
tables.
|
32
|
+
|
33
|
+
### Templates
|
34
|
+
|
35
|
+
This gem includes a template generator, which provides a basic
|
36
|
+
set of default templates (derived directly from the recommended templates
|
37
|
+
which are shown in the glass playground).
|
38
|
+
|
39
|
+
To generate the default templates, you can run the command:
|
40
|
+
|
41
|
+
rails g glass:templates
|
42
|
+
|
43
|
+
This will generate a basic series of templates under the path,
|
44
|
+
`app/views/glass` though you may want to organize them more logically,
|
45
|
+
depending on your use case
|
46
|
+
|
47
|
+
### Glass Models - (Introduction)
|
48
|
+
|
49
|
+
This gem also provides a glass model generator, which generates a timeline-item
|
50
|
+
model for your use:
|
51
|
+
|
52
|
+
For example, let's say you want to post a tweet to a user's glass timeline,
|
53
|
+
you may want to have a glass model which represents tweets. To generate that
|
54
|
+
model, you can run this command:
|
55
|
+
|
56
|
+
rails g glass:model tweet
|
57
|
+
|
58
|
+
and you will find a model generated for you in the directory,
|
59
|
+
`app/models/glass/<glassmodelname>.rb`.
|
60
|
+
|
61
|
+
It is primarly with Glass Models that you generate your glass application,
|
62
|
+
so understanding the mechanisms by which we map out over the actual google
|
63
|
+
api is probably a good idea.
|
64
|
+
|
65
|
+
If you want your timeline item to have a list of menu-items, you can specify
|
66
|
+
the menu-items in your glass model like so:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
class Glass::Tweet < Glass::TimelineItem
|
70
|
+
has_menu_item :custom_action_name,
|
71
|
+
display_name: "this is displayed",
|
72
|
+
icon_url: "http://icons.iconarchive.com/icons/enhancedlabs/lha-objects/128/Filetype-URL-icon.png",
|
73
|
+
handles_with: :custom_action_handler
|
74
|
+
end
|
75
|
+
```
|
76
|
+
### Glass Models - Menu Items
|
77
|
+
|
78
|
+
You can define a series of menu items for a glass model,
|
79
|
+
using the helper method `has_menu_item`. This method takes the
|
80
|
+
following arguments:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
class Glass::ExampleCard < Glass::TimelineItem
|
84
|
+
has_menu_item <symbolized_name_of_action>, <options>
|
85
|
+
## here options is a hash, and you can define here:
|
86
|
+
## the displayed name of the action/menu item,
|
87
|
+
## i.e. 'like', as well as a url for an icon, and
|
88
|
+
## a callback method which gets executed when you
|
89
|
+
## are notified of an event.
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
Basically, the way that the google mirror api works, you
|
94
|
+
are required to subscribe to notifications from a user to
|
95
|
+
get updated on the status of a user action on a timeline
|
96
|
+
item. This gems aims to aid the subscription and notification
|
97
|
+
process, primarily to get the process bootstrapped and ready to
|
98
|
+
go.
|
99
|
+
|
100
|
+
You will automatically be subscribed to notifications on a timeline
|
101
|
+
item, and will get notified to your glass callback url, which we have
|
102
|
+
inserted into your routes for you if you have used the install
|
103
|
+
generator.
|
104
|
+
|
105
|
+
Once you have generated a timeline item glass model:
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
class Glass::Tweet < Glass::TimelineItem
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
You can use the `has_menu_item` helper method in your
|
113
|
+
glass model to define menu items. These menu items will them be
|
114
|
+
applied uniformly for your entire class.
|
115
|
+
|
116
|
+
Once you've posted to the timeline item to the glass user's
|
117
|
+
timeline, you are registered to listen for notifications
|
118
|
+
that the user has acted on your card. You can specify a callback method
|
119
|
+
using the `has_menu_item` helper method, by passing in the
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
### Glass Models - (Posting Content)
|
124
|
+
|
125
|
+
So using our Glass::Tweet class which we created above, we
|
126
|
+
could instantiate a new instance of the class and assign it
|
127
|
+
an associated google account like so
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
gt = Glass::Tweet.new(google_account_id: GoogleAccount.first)
|
131
|
+
```
|
132
|
+
Then, you can populate an erb template with instance variables by
|
133
|
+
using the `serialize` method which is available to all subclasses
|
134
|
+
of Glass::TimelineItem (and yeah, to be clear, this includes Glass::Tweet).
|
135
|
+
For example, let's say you have the following erb template:
|
136
|
+
|
137
|
+
```erb
|
138
|
+
<article>
|
139
|
+
<h1><%= @title %></h1>
|
140
|
+
<section>
|
141
|
+
<ul>
|
142
|
+
<%= @content %>
|
143
|
+
</ul>
|
144
|
+
</section>
|
145
|
+
</article>
|
146
|
+
```
|
147
|
+
|
148
|
+
You can serialize the template for a glass::tweet instance like so:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
gt = Glass::Tweet.new(google_account_id: GoogleAccount.first)
|
152
|
+
gt.serialize({template_variables: {content: "asdfasdfasdf", title: "title"}})
|
153
|
+
```
|
154
|
+
|
155
|
+
which will basically populate the `@content` and `@title` instance variables
|
156
|
+
in the erb template, render it as a string, and get it prepped to send to the
|
157
|
+
mirror api for insertion into the timeline.
|
158
|
+
|
159
|
+
Then all you have to do is use the following command to actually insert the content:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
gt.client.insert
|
163
|
+
```
|
164
|
+
|
165
|
+
|
166
|
+
## Contributing
|
167
|
+
|
168
|
+
1. Fork it
|
169
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
170
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
171
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
172
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/glass-rails.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'glass/rails/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "glass-rails"
|
8
|
+
spec.version = Glass::Rails::VERSION
|
9
|
+
spec.authors = ["Kunal Modi", "Han Kang"]
|
10
|
+
spec.email = ["kunal@thirstlabs.com", 'han@therubyists.org']
|
11
|
+
spec.description = %q{ A framework for creating google glass applications using ruby on rails. }
|
12
|
+
spec.summary = %q{ A framework for creating google glass applications using ruby on rails.
|
13
|
+
This probably isn't for everyone, but we did our best to make it suitable for
|
14
|
+
as many cases as possible. }
|
15
|
+
spec.homepage = ""
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files`.split($/)
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
|
24
|
+
spec.add_dependency "railties", [">= 3.1"]
|
25
|
+
spec.add_dependency "google-api-client"
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
spec.add_development_dependency "pry"
|
29
|
+
spec.add_development_dependency "pry-rails"
|
30
|
+
spec.add_development_dependency "rspec", ">= 1.5.2"
|
31
|
+
spec.add_development_dependency "rspec-rails", '~> 2.11.0'
|
32
|
+
|
33
|
+
end
|
data/lib/.DS_Store
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module Glass
|
4
|
+
module Generators
|
5
|
+
class Base < Rails::Generators::Base #:nodoc:
|
6
|
+
def self.source_root
|
7
|
+
@_glass_source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'glass', generator_name, 'templates'))
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.banner
|
11
|
+
"rails generate glass:#{generator_name} #{self.arguments.map{ |a| a.usage }.join(' ')} [options]"
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def print_usage
|
17
|
+
self.class.help(Thor::Base.shell.new)
|
18
|
+
exit
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
Binary file
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'generators/glass'
|
2
|
+
require 'rails/generators'
|
3
|
+
require 'rails/generators/migration'
|
4
|
+
|
5
|
+
module Glass
|
6
|
+
module Generators
|
7
|
+
class InstallGenerator < Base
|
8
|
+
include Rails::Generators::Migration
|
9
|
+
argument :user_model, type: :string, default: "User"
|
10
|
+
|
11
|
+
def create_configuration_file
|
12
|
+
copy_file("google-oauth.yml", "config/google-api-keys.yml")
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_glass_account_migration
|
16
|
+
generate("model", "google_account token refresh_token expires_at:integer email name id_token verification_secret #{user_model.underscore.singularize}:references")
|
17
|
+
remove_file("app/models/google_account.rb")
|
18
|
+
template("google_account.rb", "app/models/google_account.rb")
|
19
|
+
insert_into_file("app/models/#{user_model.underscore.singularize}.rb", "\n\s\shas_one :google_account\n\n", after: "ActiveRecord::Base\n")
|
20
|
+
end
|
21
|
+
def self.next_migration_number(path)
|
22
|
+
(Time.now.utc.strftime("%Y%m%d%H%M%S").to_i + 1).to_s
|
23
|
+
end
|
24
|
+
def create_timeline_items_migration
|
25
|
+
migration_template "glass_timeline_item_migration.rb", "db/migrate/create_glass_timeline_items.rb"
|
26
|
+
end
|
27
|
+
def create_subscription_notifications_controller
|
28
|
+
generate("controller", "glass/notifications")
|
29
|
+
remove_file("app/controllers/glass/notifications_controller.rb")
|
30
|
+
template("notifications_controller.rb", "app/controllers/glass/notifications_controller.rb")
|
31
|
+
insert_into_file("config/routes.rb", "\n\s\spost 'glass/notifications', to: 'glass/notifications#callback', as: 'glass_notifications_callback'\n\n", after: "routes.draw\sdo\n")
|
32
|
+
end
|
33
|
+
def create_initializer
|
34
|
+
copy_file "initializer.rb", "config/initializers/glass.rb"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class CreateGlassTimelineItems < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :glass_timeline_items do |t|
|
4
|
+
t.string :type
|
5
|
+
t.references :google_account
|
6
|
+
t.string :glass_item_id
|
7
|
+
t.boolean :is_deleted
|
8
|
+
t.string :glass_etag
|
9
|
+
t.string :glass_self_link
|
10
|
+
t.string :glass_kind
|
11
|
+
t.datetime :glass_created_at
|
12
|
+
t.datetime :glass_updated_at
|
13
|
+
t.string :glass_content_type
|
14
|
+
t.text :glass_content
|
15
|
+
t.datetime :display_time
|
16
|
+
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
add_index :glass_timeline_items, :google_account_id
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
google_defaults: &google_defaults
|
2
|
+
scopes: [userinfo.email, userinfo.profile]
|
3
|
+
glass_scopes: [userinfo.email, userinfo.profile, glass.timeline]
|
4
|
+
development:
|
5
|
+
client_id: CLIENT_ID
|
6
|
+
client_secret: CLIENT_SECRET
|
7
|
+
<<: *google_defaults
|
8
|
+
test:
|
9
|
+
client_id: CLIENT_ID
|
10
|
+
client_secret: CLIENT_SECRET
|
11
|
+
<<: *google_defaults
|
12
|
+
production:
|
13
|
+
client_id: CLIENT_ID
|
14
|
+
client_secret: CLIENT_SECRET
|
15
|
+
<<: *google_defaults
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class GoogleAccount < ActiveRecord::Base
|
2
|
+
belongs_to :<%= user_model.underscore.singularize %>
|
3
|
+
attr_accessible :email, :expires_at, :name, :refresh_token, :token, :verification_secret
|
4
|
+
before_create :generate_verification_secret
|
5
|
+
after_create :subscribe_to_google_notifications
|
6
|
+
def token_expiry
|
7
|
+
Time.at(self.expires_at)
|
8
|
+
end
|
9
|
+
def has_expired_token?
|
10
|
+
token_expiry < Time.now
|
11
|
+
end
|
12
|
+
def update_google_tokens(google_auth_hash)
|
13
|
+
[:token, :id_token, :expires_at].each do |attribute|
|
14
|
+
self.send("#{attribute}=", google_auth_hash[attribute.to_s])
|
15
|
+
end
|
16
|
+
self.save
|
17
|
+
end
|
18
|
+
|
19
|
+
def subscribe_to_google_notifications
|
20
|
+
subscription = Glass::Subscription.new google_account: self
|
21
|
+
subscription.insert
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def generate_verification_secret
|
26
|
+
self.verification_secret = SecureRandom.urlsafe_base64
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
if Rails.env.development?
|
2
|
+
##
|
3
|
+
## if you've set this elsewhere you may want
|
4
|
+
## to comment this out.
|
5
|
+
##
|
6
|
+
## Glass requires this to be defined for callback url
|
7
|
+
## purposes.
|
8
|
+
##
|
9
|
+
Rails.application.routes.default_url_options[:host] = 'localhost:3000'
|
10
|
+
elsif Rails.env.test?
|
11
|
+
|
12
|
+
## setup whatever you want for default url options for your test env.
|
13
|
+
end
|
14
|
+
|
15
|
+
Glass.setup do |config|
|
16
|
+
## you can override the logo here
|
17
|
+
## config.brandname = "examplename"
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
## manually override your glass views path here.
|
22
|
+
config.glass_template_path = "app/views/glass"
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'generators/glass'
|
2
|
+
require 'rails/generators'
|
3
|
+
require 'rails/generators/migration'
|
4
|
+
|
5
|
+
module Glass
|
6
|
+
module Generators
|
7
|
+
class ModelGenerator < Base
|
8
|
+
argument :model_name, type: :string
|
9
|
+
def copy_glass_templates
|
10
|
+
unless File.directory?("app/models/glass/")
|
11
|
+
empty_directory("app/models/glass")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
def create_glass_model
|
15
|
+
template("model.rb", "app/models/glass/#{model_name.underscore}.rb")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|