riddler 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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