riddler 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +105 -6
- data/lib/riddler.rb +52 -3
- data/lib/riddler/configuration.rb +11 -0
- data/lib/riddler/context.rb +40 -2
- data/lib/riddler/context_builder.rb +35 -0
- data/lib/riddler/context_builders/faraday_builder.rb +23 -0
- data/lib/riddler/context_builders/user_agent.rb +34 -0
- data/lib/riddler/context_director.rb +67 -0
- data/lib/riddler/drops/hash_drop.rb +29 -0
- data/lib/riddler/element.rb +15 -14
- data/lib/riddler/elements/heading.rb +0 -1
- data/lib/riddler/elements/image.rb +21 -0
- data/lib/riddler/elements/link.rb +30 -0
- data/lib/riddler/elements/text.rb +17 -0
- data/lib/riddler/elements/variant.rb +21 -0
- data/lib/riddler/includeable.rb +19 -0
- data/lib/riddler/protobuf/content_definition.proto +51 -0
- data/lib/riddler/protobuf/content_definition_pb.rb +33 -0
- data/lib/riddler/protobuf/content_management.proto +35 -0
- data/lib/riddler/protobuf/content_management_pb.rb +43 -0
- data/lib/riddler/protobuf/content_management_services_pb.rb +27 -0
- data/lib/riddler/protobuf/slug.proto +61 -0
- data/lib/riddler/protobuf/slug_pb.rb +52 -0
- data/lib/riddler/step.rb +16 -16
- data/lib/riddler/steps/content.rb +5 -5
- data/lib/riddler/steps/variant.rb +23 -0
- data/lib/riddler/test_generator.rb +73 -0
- data/lib/riddler/use_cases.rb +7 -0
- data/lib/riddler/use_cases/admin_preview_step.rb +32 -0
- data/lib/riddler/use_cases/complete_interaction.rb +20 -0
- data/lib/riddler/use_cases/dismiss_interaction.rb +20 -0
- data/lib/riddler/use_cases/preview_context.rb +28 -0
- data/lib/riddler/use_cases/preview_step.rb +16 -5
- data/lib/riddler/use_cases/show_content_definition.rb +42 -0
- data/lib/riddler/use_cases/show_slug.rb +138 -0
- data/lib/riddler/version.rb +1 -1
- data/riddler.gemspec +12 -8
- metadata +100 -10
- data/.gitignore +0 -8
- data/.travis.yml +0 -7
- data/Gemfile +0 -6
- data/Gemfile.lock +0 -58
- data/Rakefile +0 -10
- data/bin/console +0 -14
- data/bin/setup +0 -8
@@ -0,0 +1,29 @@
|
|
1
|
+
module Riddler
|
2
|
+
module Drops
|
3
|
+
|
4
|
+
class HashDrop < ::Liquid::Drop
|
5
|
+
attr_reader :hash
|
6
|
+
|
7
|
+
def initialize hash
|
8
|
+
@hash = Hash[ hash.map { |k,v| [k.to_s, v] } ]
|
9
|
+
end
|
10
|
+
|
11
|
+
def []= key, value
|
12
|
+
@hash[key.to_s] = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def liquid_method_missing method
|
16
|
+
@hash[method]
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_hash
|
20
|
+
hash
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing method, *_args
|
24
|
+
liquid_method_missing method.to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/riddler/element.rb
CHANGED
@@ -1,14 +1,22 @@
|
|
1
1
|
module Riddler
|
2
|
-
|
3
2
|
class Element
|
3
|
+
include ::Riddler::Includeable
|
4
|
+
|
4
5
|
attr_reader :definition, :context
|
5
6
|
|
7
|
+
def self.subclasses
|
8
|
+
@@subclasses ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.inherited subclass
|
12
|
+
self.subclasses << subclass
|
13
|
+
end
|
14
|
+
|
6
15
|
def self.for definition, context
|
7
|
-
|
8
|
-
element_type = definition["object"]
|
16
|
+
element_type = definition["type"]
|
9
17
|
|
10
18
|
# Maybe this should be a registry
|
11
|
-
klass = subclasses.detect { |
|
19
|
+
klass = subclasses.detect { |k| k.type == element_type }
|
12
20
|
|
13
21
|
klass.new definition, context
|
14
22
|
end
|
@@ -18,20 +26,13 @@ module Riddler
|
|
18
26
|
@context = context
|
19
27
|
end
|
20
28
|
|
21
|
-
#def id
|
22
|
-
# definition["id"]
|
23
|
-
#end
|
24
|
-
|
25
|
-
#def type
|
26
|
-
# self.class.type
|
27
|
-
#end
|
28
|
-
|
29
29
|
def to_hash
|
30
30
|
{
|
31
|
+
content_type: "element",
|
31
32
|
type: self.class.type,
|
32
|
-
id: definition["id"]
|
33
|
+
id: definition["id"],
|
34
|
+
name: definition["name"]
|
33
35
|
}
|
34
36
|
end
|
35
37
|
end
|
36
|
-
|
37
38
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Riddler
|
2
|
+
module Elements
|
3
|
+
class Image < ::Riddler::Element
|
4
|
+
def self.type
|
5
|
+
"image"
|
6
|
+
end
|
7
|
+
|
8
|
+
def src
|
9
|
+
context.render definition["src"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def alt
|
13
|
+
context.render definition["alt"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_hash
|
17
|
+
super.merge alt: alt, src: src
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Riddler
|
2
|
+
module Elements
|
3
|
+
class Link < ::Riddler::Element
|
4
|
+
def self.type
|
5
|
+
"link"
|
6
|
+
end
|
7
|
+
|
8
|
+
def href
|
9
|
+
@href ||= context.render definition["href"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def link
|
13
|
+
return href if context.variable(:interaction).nil?
|
14
|
+
"/interactions/%s/redirect?element_id=%s&url=%s" % [
|
15
|
+
context.interaction.id,
|
16
|
+
definition["id"],
|
17
|
+
href
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
def text
|
22
|
+
context.render definition["text"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_hash
|
26
|
+
super.merge text: text, href: href, link: link
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Riddler
|
2
|
+
module Elements
|
3
|
+
class Varient < ::Riddler::Element
|
4
|
+
def self.type
|
5
|
+
"variant"
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_hash
|
9
|
+
included_element.to_hash
|
10
|
+
end
|
11
|
+
|
12
|
+
def included_element
|
13
|
+
definition["elements"]
|
14
|
+
.map do |hash|
|
15
|
+
::Riddler::Element.for hash, context
|
16
|
+
end
|
17
|
+
.detect(&:include?)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Riddler
|
2
|
+
module Includeable
|
3
|
+
def include?
|
4
|
+
return true unless has_include_predicate?
|
5
|
+
Predicator.evaluate include_predicate, context.to_liquid
|
6
|
+
end
|
7
|
+
|
8
|
+
def include_predicate
|
9
|
+
definition["include_predicate"]
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def has_include_predicate?
|
15
|
+
definition.key? "include_predicate" and
|
16
|
+
definition["include_predicate"].to_s.strip != ""
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
syntax = "proto3";
|
2
|
+
|
3
|
+
package riddler.protobuf;
|
4
|
+
|
5
|
+
import "google/protobuf/timestamp.proto";
|
6
|
+
|
7
|
+
/*
|
8
|
+
ContentDefinition is one of the outputs of the RiddlerAdmin app. After an admin
|
9
|
+
user has created a piece of content - it must first be approved. Once approved
|
10
|
+
it can then be published which will create the ContentDefinition in the remote
|
11
|
+
Riddler service. ContentDefinitions CAN NOT be modified. When changes are needed - a
|
12
|
+
new ContentDefinition (with a bumped version) will be created.
|
13
|
+
*/
|
14
|
+
message ContentDefinition {
|
15
|
+
string id = 1;
|
16
|
+
google.protobuf.Timestamp created_at = 2;
|
17
|
+
|
18
|
+
// Type of content: STEP
|
19
|
+
ContentType content_type = 3;
|
20
|
+
|
21
|
+
// ID of the content: st_12345
|
22
|
+
string content_id = 4;
|
23
|
+
|
24
|
+
// Version of the content. Starts at 1 and increments with each new definition
|
25
|
+
int32 version = 5;
|
26
|
+
|
27
|
+
// Title of the content: User Research Prompt
|
28
|
+
string title = 6;
|
29
|
+
|
30
|
+
// Description of the version: Adds updated images
|
31
|
+
string description = 7;
|
32
|
+
|
33
|
+
// Schema version of the definition
|
34
|
+
// The format and structure of a ContentDefinition may change over time
|
35
|
+
int32 definition_schema_version = 8;
|
36
|
+
|
37
|
+
/*
|
38
|
+
The opaque definition string generated by the admin tool (contains the
|
39
|
+
structure, predicates, liquid templates, ...). This is a snapshot of models
|
40
|
+
which belong to the admin tool.
|
41
|
+
*/
|
42
|
+
oneof definition {
|
43
|
+
string definition_string = 9;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
enum ContentType {
|
48
|
+
UNKNOWN_CONTENT_TYPE = 0;
|
49
|
+
STEP = 1;
|
50
|
+
ELEMENT = 2;
|
51
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: riddler/protobuf/content_definition.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
require 'google/protobuf/timestamp_pb'
|
7
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
8
|
+
add_message "riddler.protobuf.ContentDefinition" do
|
9
|
+
optional :id, :string, 1
|
10
|
+
optional :created_at, :message, 2, "google.protobuf.Timestamp"
|
11
|
+
optional :content_type, :enum, 3, "riddler.protobuf.ContentType"
|
12
|
+
optional :content_id, :string, 4
|
13
|
+
optional :version, :int32, 5
|
14
|
+
optional :title, :string, 6
|
15
|
+
optional :description, :string, 7
|
16
|
+
optional :definition_schema_version, :int32, 8
|
17
|
+
oneof :definition do
|
18
|
+
optional :definition_string, :string, 9
|
19
|
+
end
|
20
|
+
end
|
21
|
+
add_enum "riddler.protobuf.ContentType" do
|
22
|
+
value :UNKNOWN_CONTENT_TYPE, 0
|
23
|
+
value :STEP, 1
|
24
|
+
value :ELEMENT, 2
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module Riddler
|
29
|
+
module Protobuf
|
30
|
+
ContentDefinition = Google::Protobuf::DescriptorPool.generated_pool.lookup("riddler.protobuf.ContentDefinition").msgclass
|
31
|
+
ContentType = Google::Protobuf::DescriptorPool.generated_pool.lookup("riddler.protobuf.ContentType").enummodule
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
syntax = "proto3";
|
2
|
+
|
3
|
+
package riddler.protobuf;
|
4
|
+
|
5
|
+
import "riddler/protobuf/content_definition.proto";
|
6
|
+
import "riddler/protobuf/slug.proto";
|
7
|
+
|
8
|
+
message CreateContentDefinitionRequest {
|
9
|
+
ContentDefinition content_definition = 1;
|
10
|
+
}
|
11
|
+
message CreateContentDefinitionResponse {}
|
12
|
+
|
13
|
+
message CreateSlugRequest {
|
14
|
+
Slug slug = 1;
|
15
|
+
}
|
16
|
+
message CreateSlugResponse {}
|
17
|
+
|
18
|
+
message UpdateSlugRequest {
|
19
|
+
Slug slug = 1;
|
20
|
+
}
|
21
|
+
message UpdateSlugResponse {}
|
22
|
+
|
23
|
+
message GetSlugStatsRequest {
|
24
|
+
Slug slug = 1;
|
25
|
+
}
|
26
|
+
message GetSlugStatsResponse {
|
27
|
+
repeated SlugStats slug_stats = 1;
|
28
|
+
}
|
29
|
+
|
30
|
+
service ContentManagement {
|
31
|
+
rpc CreateContentDefinition(CreateContentDefinitionRequest) returns (CreateContentDefinitionResponse) {}
|
32
|
+
rpc CreateSlug(CreateSlugRequest) returns (CreateSlugResponse) {}
|
33
|
+
rpc UpdateSlug(UpdateSlugRequest) returns (UpdateSlugResponse) {}
|
34
|
+
rpc GetSlugStats(GetSlugStatsRequest) returns (GetSlugStatsResponse) {}
|
35
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: riddler/protobuf/content_management.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
require 'riddler/protobuf/content_definition_pb'
|
7
|
+
require 'riddler/protobuf/slug_pb'
|
8
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
9
|
+
add_message "riddler.protobuf.CreateContentDefinitionRequest" do
|
10
|
+
optional :content_definition, :message, 1, "riddler.protobuf.ContentDefinition"
|
11
|
+
end
|
12
|
+
add_message "riddler.protobuf.CreateContentDefinitionResponse" do
|
13
|
+
end
|
14
|
+
add_message "riddler.protobuf.CreateSlugRequest" do
|
15
|
+
optional :slug, :message, 1, "riddler.protobuf.Slug"
|
16
|
+
end
|
17
|
+
add_message "riddler.protobuf.CreateSlugResponse" do
|
18
|
+
end
|
19
|
+
add_message "riddler.protobuf.UpdateSlugRequest" do
|
20
|
+
optional :slug, :message, 1, "riddler.protobuf.Slug"
|
21
|
+
end
|
22
|
+
add_message "riddler.protobuf.UpdateSlugResponse" do
|
23
|
+
end
|
24
|
+
add_message "riddler.protobuf.GetSlugStatsRequest" do
|
25
|
+
optional :slug, :message, 1, "riddler.protobuf.Slug"
|
26
|
+
end
|
27
|
+
add_message "riddler.protobuf.GetSlugStatsResponse" do
|
28
|
+
repeated :slug_stats, :message, 1, "riddler.protobuf.SlugStats"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module Riddler
|
33
|
+
module Protobuf
|
34
|
+
CreateContentDefinitionRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("riddler.protobuf.CreateContentDefinitionRequest").msgclass
|
35
|
+
CreateContentDefinitionResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("riddler.protobuf.CreateContentDefinitionResponse").msgclass
|
36
|
+
CreateSlugRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("riddler.protobuf.CreateSlugRequest").msgclass
|
37
|
+
CreateSlugResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("riddler.protobuf.CreateSlugResponse").msgclass
|
38
|
+
UpdateSlugRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("riddler.protobuf.UpdateSlugRequest").msgclass
|
39
|
+
UpdateSlugResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("riddler.protobuf.UpdateSlugResponse").msgclass
|
40
|
+
GetSlugStatsRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("riddler.protobuf.GetSlugStatsRequest").msgclass
|
41
|
+
GetSlugStatsResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("riddler.protobuf.GetSlugStatsResponse").msgclass
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# Source: riddler/protobuf/content_management.proto for package 'riddler.protobuf'
|
3
|
+
|
4
|
+
require 'grpc'
|
5
|
+
require 'riddler/protobuf/content_management_pb'
|
6
|
+
|
7
|
+
module Riddler
|
8
|
+
module Protobuf
|
9
|
+
module ContentManagement
|
10
|
+
class Service
|
11
|
+
|
12
|
+
include GRPC::GenericService
|
13
|
+
|
14
|
+
self.marshal_class_method = :encode
|
15
|
+
self.unmarshal_class_method = :decode
|
16
|
+
self.service_name = 'riddler.protobuf.ContentManagement'
|
17
|
+
|
18
|
+
rpc :CreateContentDefinition, CreateContentDefinitionRequest, CreateContentDefinitionResponse
|
19
|
+
rpc :CreateSlug, CreateSlugRequest, CreateSlugResponse
|
20
|
+
rpc :UpdateSlug, UpdateSlugRequest, UpdateSlugResponse
|
21
|
+
rpc :GetSlugStats, GetSlugStatsRequest, GetSlugStatsResponse
|
22
|
+
end
|
23
|
+
|
24
|
+
Stub = Service.rpc_stub_class
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
syntax = "proto3";
|
2
|
+
|
3
|
+
package riddler.protobuf;
|
4
|
+
|
5
|
+
import "google/protobuf/timestamp.proto";
|
6
|
+
|
7
|
+
/*
|
8
|
+
Slug is one of the outputs of the RiddlerAdmin app.
|
9
|
+
It maps a URL slug to a specific ContentDefinition and allows for
|
10
|
+
control of if it is available (status) as well as a targeting predicate.
|
11
|
+
Changes to Slugs do NOT need to go through compliance approval (as they don't
|
12
|
+
allow for modification of content).
|
13
|
+
*/
|
14
|
+
message Slug {
|
15
|
+
string id = 1;
|
16
|
+
google.protobuf.Timestamp created_at = 2;
|
17
|
+
google.protobuf.Timestamp updated_at = 3;
|
18
|
+
|
19
|
+
// The URL slug used to access content: user_research_prompt
|
20
|
+
string name = 4;
|
21
|
+
|
22
|
+
// LIVE or PAUSED
|
23
|
+
SlugStatus status = 5;
|
24
|
+
|
25
|
+
// ContentDefinition to be displayed
|
26
|
+
string content_definition_id = 6;
|
27
|
+
|
28
|
+
// Liquid template to define if an interaction should be reused
|
29
|
+
string interaction_identity = 7;
|
30
|
+
|
31
|
+
// Predicate to evaluate if the content should be shown
|
32
|
+
string target_predicate = 8;
|
33
|
+
}
|
34
|
+
|
35
|
+
enum SlugStatus {
|
36
|
+
UNKNOWN_SLUG_STATUS = 0;
|
37
|
+
LIVE = 1;
|
38
|
+
PAUSED = 2;
|
39
|
+
}
|
40
|
+
|
41
|
+
enum Interval {
|
42
|
+
UNKNOWN_INTERVAL = 0;
|
43
|
+
SECOND = 1;
|
44
|
+
MINUTE = 2;
|
45
|
+
HOUR = 3;
|
46
|
+
DAY = 4;
|
47
|
+
WEEK = 5;
|
48
|
+
MONTH = 6;
|
49
|
+
QUARTER = 7;
|
50
|
+
YEAR = 8;
|
51
|
+
}
|
52
|
+
|
53
|
+
message EventCount {
|
54
|
+
string event_name = 1;
|
55
|
+
int32 count = 2;
|
56
|
+
}
|
57
|
+
|
58
|
+
message SlugStats {
|
59
|
+
Interval interval = 1;
|
60
|
+
repeated EventCount event_counts = 2;
|
61
|
+
}
|