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.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a56c1db8c7d926edb5786eb578adf7189a1b70acebcc62f7ee7e67f615f67e7f
|
4
|
+
data.tar.gz: 64b7ca5382dbee480718022ff190839d8e2bf3f6e85538dbba47214c6a95945f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0b87cca825ae1dbc3b27d226abe773b2299c5491c35a6afd8523adf4b612f5a6b84c0c61cc77493b86a10f310d5208fb954ef1568138287415f26768ede8311
|
7
|
+
data.tar.gz: 945736aaf732241402a00acb5e805ae1f1403adc67ef2d8868203b004591f6b65e0ff0a952b967764a6e95b885152f2256511fcea05db0fb11d5ee68596a6e79
|
data/LICENSE.txt
CHANGED
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
|
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/
|
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/
|
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).
|
data/lib/riddler.rb
CHANGED
@@ -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
|
32
|
+
require "riddler/use_cases"
|
15
33
|
|
16
34
|
module Riddler
|
17
35
|
class Error < StandardError; end
|
18
|
-
|
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
|
data/lib/riddler/context.rb
CHANGED
@@ -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
|