riddler 0.1.0 → 0.2.0

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +105 -6
  4. data/lib/riddler.rb +52 -3
  5. data/lib/riddler/configuration.rb +11 -0
  6. data/lib/riddler/context.rb +40 -2
  7. data/lib/riddler/context_builder.rb +35 -0
  8. data/lib/riddler/context_builders/faraday_builder.rb +23 -0
  9. data/lib/riddler/context_builders/user_agent.rb +34 -0
  10. data/lib/riddler/context_director.rb +67 -0
  11. data/lib/riddler/drops/hash_drop.rb +29 -0
  12. data/lib/riddler/element.rb +15 -14
  13. data/lib/riddler/elements/heading.rb +0 -1
  14. data/lib/riddler/elements/image.rb +21 -0
  15. data/lib/riddler/elements/link.rb +30 -0
  16. data/lib/riddler/elements/text.rb +17 -0
  17. data/lib/riddler/elements/variant.rb +21 -0
  18. data/lib/riddler/includeable.rb +19 -0
  19. data/lib/riddler/protobuf/content_definition.proto +51 -0
  20. data/lib/riddler/protobuf/content_definition_pb.rb +33 -0
  21. data/lib/riddler/protobuf/content_management.proto +35 -0
  22. data/lib/riddler/protobuf/content_management_pb.rb +43 -0
  23. data/lib/riddler/protobuf/content_management_services_pb.rb +27 -0
  24. data/lib/riddler/protobuf/slug.proto +61 -0
  25. data/lib/riddler/protobuf/slug_pb.rb +52 -0
  26. data/lib/riddler/step.rb +16 -16
  27. data/lib/riddler/steps/content.rb +5 -5
  28. data/lib/riddler/steps/variant.rb +23 -0
  29. data/lib/riddler/test_generator.rb +73 -0
  30. data/lib/riddler/use_cases.rb +7 -0
  31. data/lib/riddler/use_cases/admin_preview_step.rb +32 -0
  32. data/lib/riddler/use_cases/complete_interaction.rb +20 -0
  33. data/lib/riddler/use_cases/dismiss_interaction.rb +20 -0
  34. data/lib/riddler/use_cases/preview_context.rb +28 -0
  35. data/lib/riddler/use_cases/preview_step.rb +16 -5
  36. data/lib/riddler/use_cases/show_content_definition.rb +42 -0
  37. data/lib/riddler/use_cases/show_slug.rb +138 -0
  38. data/lib/riddler/version.rb +1 -1
  39. data/riddler.gemspec +12 -8
  40. metadata +100 -10
  41. data/.gitignore +0 -8
  42. data/.travis.yml +0 -7
  43. data/Gemfile +0 -6
  44. data/Gemfile.lock +0 -58
  45. data/Rakefile +0 -10
  46. data/bin/console +0 -14
  47. 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
@@ -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
- # This should be "type" not "object"
8
- element_type = definition["object"]
16
+ element_type = definition["type"]
9
17
 
10
18
  # Maybe this should be a registry
11
- klass = subclasses.detect { |klass| klass.type == element_type }
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
@@ -14,6 +14,5 @@ module Riddler
14
14
  super.merge text: text
15
15
  end
16
16
  end
17
-
18
17
  end
19
18
  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,17 @@
1
+ module Riddler
2
+ module Elements
3
+ class Text < ::Riddler::Element
4
+ def self.type
5
+ "text"
6
+ end
7
+
8
+ def text
9
+ context.render definition["text"]
10
+ end
11
+
12
+ def to_hash
13
+ super.merge text: text
14
+ end
15
+ end
16
+ end
17
+ 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
+ }