ask_awesomely 0.1.2
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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/README.md +474 -0
- data/Rakefile +11 -0
- data/ask_awesomely.gemspec +27 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/ask_awesomely.rb +31 -0
- data/lib/ask_awesomely/api_client.rb +56 -0
- data/lib/ask_awesomely/choice.rb +10 -0
- data/lib/ask_awesomely/configuration.rb +30 -0
- data/lib/ask_awesomely/dsl.rb +50 -0
- data/lib/ask_awesomely/embeddable.rb +30 -0
- data/lib/ask_awesomely/embeds/drawer.erb +3 -0
- data/lib/ask_awesomely/embeds/fullscreen.erb +28 -0
- data/lib/ask_awesomely/embeds/modal.erb +3 -0
- data/lib/ask_awesomely/embeds/widget.erb +3 -0
- data/lib/ask_awesomely/field.rb +18 -0
- data/lib/ask_awesomely/field/dropdown.rb +18 -0
- data/lib/ask_awesomely/field/email.rb +5 -0
- data/lib/ask_awesomely/field/field.rb +68 -0
- data/lib/ask_awesomely/field/legal.rb +4 -0
- data/lib/ask_awesomely/field/long_text.rb +9 -0
- data/lib/ask_awesomely/field/multiple_choice.rb +30 -0
- data/lib/ask_awesomely/field/number.rb +22 -0
- data/lib/ask_awesomely/field/opinion_scale.rb +40 -0
- data/lib/ask_awesomely/field/picture_choice.rb +34 -0
- data/lib/ask_awesomely/field/rating.rb +31 -0
- data/lib/ask_awesomely/field/short_text.rb +9 -0
- data/lib/ask_awesomely/field/statement.rb +21 -0
- data/lib/ask_awesomely/field/website.rb +4 -0
- data/lib/ask_awesomely/field/yes_no.rb +4 -0
- data/lib/ask_awesomely/picture.rb +41 -0
- data/lib/ask_awesomely/s3.rb +51 -0
- data/lib/ask_awesomely/typeform.rb +43 -0
- data/lib/ask_awesomely/version.rb +3 -0
- metadata +166 -0
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ask_awesomely/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ask_awesomely"
|
8
|
+
spec.version = AskAwesomely::VERSION
|
9
|
+
spec.authors = ["Lee Machin"]
|
10
|
+
spec.email = ["me@mrl.ee"]
|
11
|
+
|
12
|
+
spec.summary = "Create Typeforms on the fly, the Typeform way."
|
13
|
+
spec.homepage = "https://github.com/leemachin/ask_awesomely"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = "exe"
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "aws-sdk", "~> 2.0"
|
21
|
+
spec.add_dependency "typhoeus", "~> 0.8"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.9"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.8"
|
26
|
+
spec.add_development_dependency "vcr", "~> 2.9"
|
27
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "ask_awesomely"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require "ask_awesomely/version"
|
2
|
+
require "ask_awesomely/configuration"
|
3
|
+
require "ask_awesomely/dsl"
|
4
|
+
require "ask_awesomely/field"
|
5
|
+
require "ask_awesomely/choice"
|
6
|
+
require "ask_awesomely/picture"
|
7
|
+
require "ask_awesomely/s3"
|
8
|
+
require "ask_awesomely/api_client"
|
9
|
+
require "ask_awesomely/typeform"
|
10
|
+
require "ask_awesomely/embeddable"
|
11
|
+
|
12
|
+
require "erb"
|
13
|
+
require "json"
|
14
|
+
require "aws-sdk"
|
15
|
+
require "typhoeus"
|
16
|
+
|
17
|
+
module AskAwesomely
|
18
|
+
|
19
|
+
ConfigurationError = Class.new(ArgumentError)
|
20
|
+
FieldTypeError = Class.new(ArgumentError)
|
21
|
+
EmbedTypeError = Class.new(ArgumentError)
|
22
|
+
|
23
|
+
def self.configuration
|
24
|
+
@configuration ||= Configuration.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.configure(&block)
|
28
|
+
block.call(self.configuration)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module AskAwesomely
|
2
|
+
class ApiClient
|
3
|
+
|
4
|
+
USER_AGENT = "leemachin/ask_awesomely; (v#{AskAwesomely::VERSION})"
|
5
|
+
BASE_URL = "https://api.typeform.io/latest"
|
6
|
+
ENDPOINTS = {
|
7
|
+
root: "/",
|
8
|
+
create_typeform: "/forms"
|
9
|
+
}
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
Typhoeus::Config.user_agent = USER_AGENT
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_info
|
16
|
+
response = request.get(
|
17
|
+
url_for(:root),
|
18
|
+
headers: headers
|
19
|
+
)
|
20
|
+
|
21
|
+
JSON.parse(response.body)
|
22
|
+
end
|
23
|
+
|
24
|
+
def submit_typeform(typeform)
|
25
|
+
response = request.post(
|
26
|
+
url_for(:create_typeform),
|
27
|
+
headers: headers,
|
28
|
+
body: typeform.to_json
|
29
|
+
)
|
30
|
+
|
31
|
+
typeform.tap do |tf|
|
32
|
+
body = JSON.parse(response.body)
|
33
|
+
tf.update_with_api_response(body)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def request
|
40
|
+
Typhoeus::Request
|
41
|
+
end
|
42
|
+
|
43
|
+
def url_for(endpoint)
|
44
|
+
BASE_URL + ENDPOINTS[endpoint]
|
45
|
+
end
|
46
|
+
|
47
|
+
def headers(others = {})
|
48
|
+
others.merge({
|
49
|
+
"X-API-TOKEN" => AskAwesomely.configuration.typeform_api_key,
|
50
|
+
"Accept" => "application/json",
|
51
|
+
"Content-Type" => "application/json"
|
52
|
+
})
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module AskAwesomely
|
2
|
+
class Configuration
|
3
|
+
|
4
|
+
DEFAULT_AWS_BUCKET = "typeform_io_images"
|
5
|
+
DEFAULT_AWS_REGION = "us-east-1"
|
6
|
+
|
7
|
+
attr_accessor :typeform_api_key,
|
8
|
+
:aws_access_key_id,
|
9
|
+
:aws_access_key_secret,
|
10
|
+
:aws_region,
|
11
|
+
:aws_bucket
|
12
|
+
|
13
|
+
def typeform_api_key
|
14
|
+
unless @typeform_api_key
|
15
|
+
raise ConfigurationError, "Typeform I/O API Key must be set before use, get one from <https://typeform.io>."
|
16
|
+
end
|
17
|
+
|
18
|
+
@typeform_api_key
|
19
|
+
end
|
20
|
+
|
21
|
+
def aws_region
|
22
|
+
@aws_region || DEFAULT_AWS_REGION
|
23
|
+
end
|
24
|
+
|
25
|
+
def aws_bucket
|
26
|
+
@aws_bucket || DEFAULT_AWS_BUCKET
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module AskAwesomely
|
2
|
+
module DSL
|
3
|
+
|
4
|
+
def self.included(recv)
|
5
|
+
recv.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def _api_client
|
10
|
+
@api_client = ApiClient.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def _state
|
14
|
+
@state ||= OpenStruct.new(
|
15
|
+
title: "",
|
16
|
+
fields: []
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def build(context = nil)
|
21
|
+
structure = new(context)
|
22
|
+
typeform = Typeform.new(structure)
|
23
|
+
_api_client.submit_typeform(typeform)
|
24
|
+
end
|
25
|
+
|
26
|
+
def title(title)
|
27
|
+
_state.title = title
|
28
|
+
end
|
29
|
+
|
30
|
+
def tags(*tags)
|
31
|
+
_state.tags = tags
|
32
|
+
end
|
33
|
+
|
34
|
+
def field(type, &block)
|
35
|
+
_state.fields << Field::Field.of_type(type, &block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :context, :json
|
40
|
+
|
41
|
+
private def initialize(context = nil)
|
42
|
+
@context = context
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_json
|
46
|
+
self.class._state.to_h.to_json
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module AskAwesomely
|
2
|
+
class Embeddable
|
3
|
+
|
4
|
+
EMBED_TYPES = %i(
|
5
|
+
modal
|
6
|
+
drawer
|
7
|
+
widget
|
8
|
+
fullscreen
|
9
|
+
)
|
10
|
+
|
11
|
+
def initialize(embed_type)
|
12
|
+
unless EMBED_TYPES.include?(embed_type)
|
13
|
+
raise AskAwesomely::EmbedTypeError, "embed type must be one of: #{EMBED_TYPES.join(', ')}"
|
14
|
+
end
|
15
|
+
|
16
|
+
@embed_type = embed_type
|
17
|
+
end
|
18
|
+
|
19
|
+
def render(typeform)
|
20
|
+
ERB.new(template, 0, '>').result(typeform.get_binding)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def template
|
26
|
+
Pathname.new(__dir__).join("embeds", "#{@embed_type}.erb").read
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,3 @@
|
|
1
|
+
<a class="typeform-share link" href="<%= public_url %>" data-mode="2" target="_blank">Launch me!</a>
|
2
|
+
|
3
|
+
<script>(function(){var qs,js,q,s,d=document,gi=d.getElementById,ce=d.createElement,gt=d.getElementsByTagName,id='typef_orm',b='https://s3-eu-west-1.amazonaws.com/share.typeform.com/';if(!gi.call(d,id)){js=ce.call(d,'script');js.id=id;js.src=b+'share.js';q=gt.call(d,'script')[0];q.parentNode.insertBefore(js,q)}})()</script>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<!--Add the title of your typeform below-->
|
5
|
+
<title><%= title %></title>
|
6
|
+
|
7
|
+
<!--CSS styles that ensure your typeform takes up all the available screen space (DO NOT EDIT!)-->
|
8
|
+
<style type="text/css">
|
9
|
+
html{
|
10
|
+
margin: 0;
|
11
|
+
height: 100%;
|
12
|
+
overflow: hidden;
|
13
|
+
}
|
14
|
+
iframe{
|
15
|
+
position: absolute;
|
16
|
+
left:0;
|
17
|
+
right:0;
|
18
|
+
bottom:0;
|
19
|
+
top:0;
|
20
|
+
border:0;
|
21
|
+
}
|
22
|
+
</style>
|
23
|
+
</head>
|
24
|
+
<body>
|
25
|
+
<iframe id="typeform-full" width="100%" height="100%" frameborder="0" src="<%= public_url %>"></iframe>
|
26
|
+
<script type="text/javascript" src="https://s3-eu-west-1.amazonaws.com/share.typeform.com/embed.js"></script>
|
27
|
+
</body>
|
28
|
+
</html>
|
@@ -0,0 +1,3 @@
|
|
1
|
+
<a class="typeform-share link" href="<%= public_url %>" data-mode="1" target="_blank">Launch me!</a>
|
2
|
+
|
3
|
+
<script>(function(){var qs,js,q,s,d=document,gi=d.getElementById,ce=d.createElement,gt=d.getElementsByTagName,id='typef_orm',b='https://s3-eu-west-1.amazonaws.com/share.typeform.com/';if(!gi.call(d,id)){js=ce.call(d,'script');js.id=id;js.src=b+'share.js';q=gt.call(d,'script')[0];q.parentNode.insertBefore(js,q)}})()</script>
|
@@ -0,0 +1,3 @@
|
|
1
|
+
<div class="typeform-widget" data-url="<%= public_url %>" data-text="<%= title %>" style="width:100%;height:500px;"></div>
|
2
|
+
|
3
|
+
<script>(function(){var qs,js,q,s,d=document,gi=d.getElementById,ce=d.createElement,gt=d.getElementsByTagName,id='typef_orm',b='https://s3-eu-west-1.amazonaws.com/share.typeform.com/';if(!gi.call(d,id)){js=ce.call(d,'script');js.id=id;js.src=b+'widget.js';q=gt.call(d,'script')[0];q.parentNode.insertBefore(js,q)}})()</script>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module AskAwesomely
|
2
|
+
module Field
|
3
|
+
require "ask_awesomely/field/field"
|
4
|
+
require "ask_awesomely/field/short_text"
|
5
|
+
require "ask_awesomely/field/long_text"
|
6
|
+
require "ask_awesomely/field/multiple_choice"
|
7
|
+
require "ask_awesomely/field/picture_choice"
|
8
|
+
require "ask_awesomely/field/statement"
|
9
|
+
require "ask_awesomely/field/number"
|
10
|
+
require "ask_awesomely/field/dropdown"
|
11
|
+
require "ask_awesomely/field/yes_no"
|
12
|
+
require "ask_awesomely/field/rating"
|
13
|
+
require "ask_awesomely/field/opinion_scale"
|
14
|
+
require "ask_awesomely/field/email"
|
15
|
+
require "ask_awesomely/field/website"
|
16
|
+
require "ask_awesomely/field/legal"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module AskAwesomely
|
2
|
+
class Field::Dropdown < Field::Field
|
3
|
+
|
4
|
+
def initialize(*)
|
5
|
+
super
|
6
|
+
@state.choices = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def choice(label)
|
10
|
+
@state.choices << Choice.new(label: label)
|
11
|
+
end
|
12
|
+
|
13
|
+
def in_alphabetical_order
|
14
|
+
@state.alphabetical_order = true
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module AskAwesomely
|
2
|
+
class Field::Field
|
3
|
+
|
4
|
+
VALID_FIELD_TYPES = %i(
|
5
|
+
short_text
|
6
|
+
long_text
|
7
|
+
multiple_choice
|
8
|
+
picture_choice
|
9
|
+
statement
|
10
|
+
dropdown
|
11
|
+
yes_no
|
12
|
+
number
|
13
|
+
rating
|
14
|
+
opinion_scale
|
15
|
+
email
|
16
|
+
website
|
17
|
+
legal
|
18
|
+
).freeze
|
19
|
+
|
20
|
+
attr_reader :state
|
21
|
+
|
22
|
+
# todo: make this easier to maintain
|
23
|
+
def self.of_type(type, &block)
|
24
|
+
field = case type
|
25
|
+
when :short_text then Field::ShortText
|
26
|
+
when :long_text then Field::LongText
|
27
|
+
when :multiple_choice then Field::MultipleChoice
|
28
|
+
when :picture_choice then Field::PictureChoice
|
29
|
+
when :statement then Field::Statement
|
30
|
+
when :dropdown then Field::Dropdown
|
31
|
+
when :yes_no then Field::YesNo
|
32
|
+
when :number then Field::Number
|
33
|
+
when :rating then Field::Rating
|
34
|
+
when :opinion_scale then Field::OpinionScale
|
35
|
+
when :email then Field::Email
|
36
|
+
when :website then Field::Website
|
37
|
+
when :legal then Field::Legal
|
38
|
+
else
|
39
|
+
raise FieldTypeError, "This type of field does not exist, please use one of: #{VALID_FIELD_TYPES.join(", ")}"
|
40
|
+
end
|
41
|
+
|
42
|
+
field.new(type, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Allow init with properties common to *all* fields
|
46
|
+
def initialize(type, &block)
|
47
|
+
@state = OpenStruct.new(type: type)
|
48
|
+
|
49
|
+
self.instance_eval(&block) if block_given?
|
50
|
+
end
|
51
|
+
|
52
|
+
def ask(question)
|
53
|
+
@state.question = question
|
54
|
+
end
|
55
|
+
|
56
|
+
def required
|
57
|
+
@state.required = true
|
58
|
+
end
|
59
|
+
|
60
|
+
def tags(*tags)
|
61
|
+
@state.tags = tags
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_json(*args)
|
65
|
+
@state.to_h.to_json(*args)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|