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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b32f298a7e738b115d8f94de7f1262566920a8ccc3acf51ae18c5219059772a
4
- data.tar.gz: 65b5aaae401daf2614a0d0b63cf24c316b0016b6d444c534f4e026ab3584ad13
3
+ metadata.gz: a56c1db8c7d926edb5786eb578adf7189a1b70acebcc62f7ee7e67f615f67e7f
4
+ data.tar.gz: 64b7ca5382dbee480718022ff190839d8e2bf3f6e85538dbba47214c6a95945f
5
5
  SHA512:
6
- metadata.gz: d2a7ad3240490a19b32b775d05b1dee2087949f73e49a489ea66d1e9a9562ea7dcfcbcc3386fe819dd6bbc935af30d9fa4cce6931c7d87ff5fe49a95d7260f8a
7
- data.tar.gz: 7bb507769931285c23feb392f46e57adfd107130465d355357aaa42f7ace4e70b54fe6fc31af798451173e38f3d723a4306810b858562ba62a1cfff8772f2af7
6
+ metadata.gz: b0b87cca825ae1dbc3b27d226abe773b2299c5491c35a6afd8523adf4b612f5a6b84c0c61cc77493b86a10f310d5208fb954ef1568138287415f26768ede8311
7
+ data.tar.gz: 945736aaf732241402a00acb5e805ae1f1403adc67ef2d8868203b004591f6b65e0ff0a952b967764a6e95b885152f2256511fcea05db0fb11d5ee68596a6e79
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2018 JohnnyT
3
+ Copyright (c) 2018-2019 John Thornton
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -2,12 +2,114 @@
2
2
 
3
3
  Riddler is a dynamic content and workflow engine.
4
4
 
5
+ ## Usage
6
+
7
+ ### Basic Example (using Liquid)
8
+
9
+ Riddler combines a ContentDefinition with a Context to render the output (using
10
+ Liquid - https://shopify.github.io/liquid/)
11
+
12
+ ```ruby
13
+ require "riddler"
14
+
15
+ content_definition = {
16
+ "id"=>"el_text",
17
+ "name"=>"text",
18
+ "content_type"=>"element",
19
+ "type"=>"text",
20
+ "text"=>"Hello {{ params.name }}!"
21
+ }
22
+
23
+ Riddler.render content_definition
24
+
25
+ # {:content_type=>"element", :type=>"text", :id=>"el_text", :name=>"text", :text=>"Hello !"}
26
+
27
+ Riddler.render content_definition, params: {name: "World"}
28
+
29
+ # {:content_type=>"element", :type=>"text", :id=>"el_text", :name=>"text", :text=>"Hello World!"}
30
+ ```
31
+
32
+ ### Predicate Example (using Predicator)
33
+
34
+ Pieces of content can define if they should be included or not. Here we use the
35
+ `include_predicate` to specify that it should only be included if `params.name = 'foo'`.
36
+
37
+ ```ruby
38
+ require "riddler"
39
+
40
+ content_definition = {
41
+ "id"=>"el_text",
42
+ "name"=>"text",
43
+ "content_type"=>"element",
44
+ "type"=>"text",
45
+ "text"=>"Hello {{ params.name }}!",
46
+ "include_predicate" => "params.name = 'foo'"
47
+ }
48
+
49
+ Riddler.render content_definition
50
+
51
+ # nil
52
+
53
+ Riddler.render content_definition, params: {name: "foo"}
54
+
55
+ # {:content_type=>"element", :type=>"text", :id=>"el_text", :name=>"text", :text=>"Hello foo!"}
56
+ ```
57
+
58
+
59
+ ### PokeAPI ContextBuilder example
60
+
61
+ One way Riddler can be extended is by adding new ContextBuilders. Let's add the ability to look up a Pokemon at https://pokeapi.co/
62
+
63
+ We will then pass in a `pokemon_id` as a param
64
+
65
+ This also shows Liquid filters - capitalizing the name
66
+
67
+ ```ruby
68
+ require "riddler"
69
+ require "net/http"
70
+
71
+ class PokemonContextBuilder < ::Riddler::ContextBuilder
72
+ # Does the current context have the data available for this builder to function
73
+ def data_available?
74
+ context.params.pokemon_id
75
+ end
76
+
77
+ # Extract IDs from the context (params, headers, JWTs, etc) and store
78
+ # them in context.ids
79
+ def extract_ids
80
+ add_id :pokemon_id, context.params.pokemon_id
81
+ end
82
+
83
+ def process
84
+ uri = URI "https://pokeapi.co/api/v2/pokemon/#{pokemon_id}/"
85
+ response_string = Net::HTTP.get uri
86
+ response = JSON.parse response_string
87
+
88
+ context.assign "pokemon", response
89
+ end
90
+ end
91
+
92
+ Riddler.configure { |c| c.context_builders << PokemonContextBuilder }
93
+
94
+ content_definition = {
95
+ "id"=>"el_text",
96
+ "name"=>"text",
97
+ "content_type"=>"element",
98
+ "type"=>"text",
99
+ "text"=>"Hello {{ pokemon.name | capitalize }}!"
100
+ }
101
+
102
+ Riddler.render content_definition, params: {pokemon_id: "1"}
103
+
104
+ # {:content_type=>"element", :type=>"text", :id=>"el_text", :name=>"text", :text=>"Hello Bulbasaur!"}
105
+ ```
106
+
5
107
  ## Installation
6
108
 
7
109
  Add this line to your application's Gemfile:
8
110
 
9
111
  ```ruby
10
- gem 'riddler'
112
+ gem "riddler"
11
113
  ```
12
114
 
13
115
  And then execute:
@@ -18,9 +120,6 @@ Or install it yourself as:
18
120
 
19
121
  $ gem install riddler
20
122
 
21
- ## Usage
22
-
23
- TODO: Write usage instructions here
24
123
 
25
124
  ## Development
26
125
 
@@ -30,7 +129,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
30
129
 
31
130
  ## Contributing
32
131
 
33
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/riddler. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
132
+ Bug reports and pull requests are welcome on GitHub at https://github.com/riddler/riddler. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
34
133
 
35
134
  ## License
36
135
 
@@ -38,4 +137,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
38
137
 
39
138
  ## Code of Conduct
40
139
 
41
- Everyone interacting in the Riddler project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/riddler/blob/master/CODE_OF_CONDUCT.md).
140
+ Everyone interacting in the Riddler project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/riddler/riddler/blob/master/CODE_OF_CONDUCT.md).
@@ -1,19 +1,68 @@
1
1
  require "riddler/version"
2
2
 
3
+ require "faraday"
4
+ require "faraday_middleware"
3
5
  require "liquid"
6
+ require "outlog"
7
+ require "predicator"
8
+ require "ulid"
4
9
 
10
+ require "riddler/includeable"
11
+
12
+ require "riddler/drops/hash_drop"
13
+
14
+ require "riddler/configuration"
15
+
16
+ require "riddler/context_builder"
17
+ require "riddler/context_builders/faraday_builder"
18
+ require "riddler/context_director"
5
19
  require "riddler/context"
6
20
 
7
21
  require "riddler/element"
8
- require "riddler/elements/copy"
9
22
  require "riddler/elements/heading"
23
+ require "riddler/elements/image"
24
+ require "riddler/elements/link"
25
+ require "riddler/elements/text"
26
+ require "riddler/elements/variant"
10
27
 
11
28
  require "riddler/step"
12
29
  require "riddler/steps/content"
30
+ require "riddler/steps/variant"
13
31
 
14
- require "riddler/use_cases/preview_step"
32
+ require "riddler/use_cases"
15
33
 
16
34
  module Riddler
17
35
  class Error < StandardError; end
18
- # Your code goes here...
36
+
37
+ def self.configure
38
+ yield configuration
39
+ end
40
+
41
+ def self.configuration
42
+ @configuration ||= ::Riddler::Configuration.new
43
+ end
44
+
45
+ def self.config; configuration; end
46
+
47
+ def self.logger
48
+ @logger ||= ::Outlog.logger
49
+ end
50
+
51
+ def self.render content_definition, context={}
52
+ unless context.kind_of? ::Riddler::Context
53
+ director = ::Riddler::ContextDirector.new context
54
+ context = director.context
55
+ end
56
+
57
+ case content_definition["content_type"]
58
+ when "element"
59
+ content = ::Riddler::Element.for content_definition, context
60
+ when "step"
61
+ content = ::Riddler::Step.for content_definition, context
62
+ end
63
+
64
+ return nil unless content.include?
65
+
66
+ content.to_hash
67
+ end
19
68
  end
@@ -0,0 +1,11 @@
1
+ module Riddler
2
+
3
+ class Configuration
4
+ attr_accessor :context_builders
5
+
6
+ def initialize
7
+ @context_builders = []
8
+ end
9
+ end
10
+
11
+ end
@@ -5,20 +5,58 @@ module Riddler
5
5
 
6
6
  def initialize input = nil
7
7
  input ||= {}
8
- @variables = {}
8
+ @variables = {
9
+ "ids" => {}
10
+ }
9
11
  input.each do |key, value|
12
+ next if value.nil?
10
13
  assign key, value
11
14
  end
12
15
  end
13
16
 
14
17
  def assign name, value
15
- variables[name.to_s] = value
18
+ variables[name.to_s] = drop_for value
19
+ end
20
+
21
+ def variable name
22
+ variables[name.to_s]
16
23
  end
17
24
 
18
25
  def render string
19
26
  template = ::Liquid::Template.parse string
20
27
  template.render variables
21
28
  end
29
+
30
+ def add_id name, value
31
+ variables["ids"][name.to_s] = value
32
+ end
33
+
34
+ def to_liquid
35
+ Liquid::Context.new [variables]
36
+ end
37
+
38
+ def to_hash
39
+ hash_array = variables.map do |key, value|
40
+ [key, value.to_hash]
41
+ end
42
+ Hash[hash_array]
43
+ end
44
+
45
+ def method_missing method_name, *_args
46
+ return super unless variables.key? method_name.to_s
47
+ variable method_name
48
+ end
49
+
50
+ private
51
+
52
+ def drop_for data
53
+ case data
54
+ when ::Liquid::Drop
55
+ data
56
+ else
57
+ ::Riddler::Drops::HashDrop.new data
58
+ end
59
+ end
22
60
  end
23
61
 
24
62
  end
@@ -0,0 +1,35 @@
1
+ module Riddler
2
+ class ContextBuilder
3
+ attr_reader :context
4
+
5
+ def initialize context
6
+ @context = context
7
+ end
8
+
9
+ # Does the current context have the data available for this builder
10
+ # to function
11
+ def data_available?
12
+ true
13
+ end
14
+
15
+ # Extract IDs from the context (params, headers, JWTs, etc) and store
16
+ # them in context.ids
17
+ def extract_ids
18
+ # no-op
19
+ end
20
+
21
+ # Inspect context for identifiers or data.
22
+ # Add any additional relevant information to the context
23
+ def process
24
+ # no-op
25
+ end
26
+
27
+ private
28
+
29
+ # Adds the ID to the context and defines a method for the ID
30
+ def add_id name, value
31
+ context.add_id name, value
32
+ define_singleton_method(name) { value }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ module Riddler
2
+ module ContextBuilders
3
+ class FaradayBuilder < ::Riddler::ContextBuilder
4
+ def self.base_uri
5
+ raise "The Faraday builder must define a class .base_uri method"
6
+ end
7
+
8
+ def connection
9
+ @connection ||= build_connection
10
+ end
11
+
12
+ private
13
+
14
+ def build_connection
15
+ Faraday.new url: self.class.base_uri do |conn|
16
+ conn.response :json, :content_type => /\bjson$/
17
+ conn.request :url_encoded
18
+ conn.adapter Faraday.default_adapter
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ require "browser/aliases"
2
+ Browser::Base.include Browser::Aliases
3
+
4
+ module Riddler
5
+ module ContextBuilders
6
+
7
+ class UserAgent < ::Riddler::ContextBuilder
8
+ # Look for the user_agent header and build a drop for that
9
+ def process
10
+ drop = UserAgentDrop.new context.headers.user_agent
11
+ context.assign "user_agent", drop
12
+ end
13
+ end
14
+
15
+ class UserAgentDrop < ::Liquid::Drop
16
+ attr_reader :user_agent, :browser
17
+
18
+ def initialize user_agent
19
+ @user_agent = user_agent
20
+ @browser = Browser.new user_agent
21
+ end
22
+
23
+ def liquid_method_missing method
24
+ browser.public_send method
25
+ end
26
+
27
+ def method_missing method, *_args
28
+ return super unless browser.respond_to? method
29
+ liquid_method_missing method
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,67 @@
1
+ module Riddler
2
+
3
+ class ContextDirector
4
+ attr_reader :params, :headers
5
+
6
+ def initialize options={}
7
+ options = {} if options.nil?
8
+ @params = options[:params] || options["params"]
9
+ @headers = options[:headers] || options["headers"]
10
+ @ctx = ::Riddler::Context.new params: params, headers: headers
11
+ @ids_extracted = false
12
+ @builders_applied = false
13
+ end
14
+
15
+ # Return the context with only IDs extracted
16
+ def simple_context
17
+ extract_ids
18
+ @ctx
19
+ end
20
+
21
+ # Create a new context and use registered builders to fill it in
22
+ def context
23
+ extract_ids
24
+ apply_builders
25
+ @ctx
26
+ end
27
+
28
+ private
29
+
30
+ def extract_ids
31
+ return if @ids_extracted
32
+
33
+ builders.each do |builder|
34
+ unless builder.data_available?
35
+ ::Riddler.logger.debug "data not available for builder", context_builder: builder.class.name
36
+ next
37
+ end
38
+ ::Riddler.logger.debug "extracting ids", context_builder: builder.class.name
39
+ builder.extract_ids
40
+ end
41
+
42
+ @ids_extracted = true
43
+ end
44
+
45
+ def apply_builders
46
+ return if @builders_applied
47
+
48
+ builders.each do |builder|
49
+ unless builder.data_available?
50
+ ::Riddler.logger.debug "data not available for builder", context_builder: builder.class.name
51
+ next
52
+ end
53
+ ::Riddler.logger.debug "processing context builder", context_builder: builder.class.name
54
+ builder.process
55
+ end
56
+
57
+ @builders_applied = true
58
+ end
59
+
60
+ def builders
61
+ @builders ||= ::Riddler.configuration.context_builders.map do |builder_class|
62
+ builder_class.new @ctx
63
+ end
64
+ end
65
+ end
66
+
67
+ end