serendipitous 0.0.1
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 +7 -0
- data/lib/serendipitous/content.rb +20 -0
- data/lib/serendipitous/content_service.rb +26 -0
- data/lib/serendipitous/prompt_service.rb +10 -0
- data/lib/serendipitous/question_service.rb +71 -0
- data/lib/serendipitous/suggestion_service.rb +10 -0
- data/lib/serendipitous/template_service.rb +39 -0
- data/lib/serendipitous.rb +24 -0
- metadata +50 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 3fbb7d75ff3884429bbb8f5950a783c8ae1fa1c6
|
|
4
|
+
data.tar.gz: 10d6ab78198c81212a8d3b5cc5c955b4d359b37c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 85cb1fd1e3278b58f7227cb0a01e52f0d3f53247d04f74272147eeda62b7bf8409af0f9515acc4476ce8b00493d9b5134abd7657fb49fb30693fa926804aec7d
|
|
7
|
+
data.tar.gz: d0cce11fa0d840528c2198bcec0e32d6d5487c25ffa68f3bcb274ae9669029926326717c93ffacb6b8a0602736f3bd7d4bbe0bb584f72870080c85676c9e2aff
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Temp Content class stand-in for notebook gem
|
|
2
|
+
class Content
|
|
3
|
+
attr_reader :data
|
|
4
|
+
|
|
5
|
+
def initialize fields={}
|
|
6
|
+
defaults = {
|
|
7
|
+
type: 'Character',
|
|
8
|
+
title: '',
|
|
9
|
+
description: ''
|
|
10
|
+
}
|
|
11
|
+
@data = defaults.merge(fields)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# TODO: find jesus
|
|
15
|
+
def method_missing method
|
|
16
|
+
# TODO: Does this let you data[method][some_list][some_value]
|
|
17
|
+
data[method]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# A layer of higher level methods on top of Content
|
|
2
|
+
class ContentService
|
|
3
|
+
def self.unanswered_fields(content)
|
|
4
|
+
content.data.select do |key, value|
|
|
5
|
+
next if blacklisted_fields.include? key
|
|
6
|
+
#next unless whitelisted_fields.include? key
|
|
7
|
+
|
|
8
|
+
unanswered?(value)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.unanswered?(field)
|
|
13
|
+
# TODO: Compare against defaults
|
|
14
|
+
field.length == 0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# TODO: make this smarter
|
|
18
|
+
def self.whitelisted_fields
|
|
19
|
+
@whitelisted_fields ||= %w(title description some_blank_field)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# TODO: make this smarter
|
|
23
|
+
def self.blacklisted_fields
|
|
24
|
+
@blacklisted_fields ||= %w(id user_id)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# TODO: scope this class (and all other classes) into Serendipity:: namespace
|
|
2
|
+
# TODO: mix multiple pieces of content
|
|
3
|
+
# TODO: specify parameters such as genre, reading level, etc
|
|
4
|
+
|
|
5
|
+
# Looks at a piece of content and provides a writing prompt about it
|
|
6
|
+
class PromptService
|
|
7
|
+
def self.prompt(content)
|
|
8
|
+
"What is #{content}?"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# TODO: scope this class (and all other classes) into Serendipity:: namespace
|
|
2
|
+
# Takes a look at a Content and asks a question about it
|
|
3
|
+
class QuestionService
|
|
4
|
+
def self.question(content)
|
|
5
|
+
# TODO: Make "What is" a token based on content type + field
|
|
6
|
+
# e.g. location-reference --> "Where is _____?""
|
|
7
|
+
field_to_answer = answerable_fields_for(content).keys.sample
|
|
8
|
+
puts "Answerable_fields: #{answerable_fields_for(content).keys}"
|
|
9
|
+
build_question content, field_to_answer
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.answerable_fields_for(content)
|
|
13
|
+
# TODO: aggregate QuestionServiceLayer responses here
|
|
14
|
+
ContentService.unanswered_fields(content)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.build_question content, field
|
|
18
|
+
type = field_type(field)
|
|
19
|
+
template = questions_for(type).sample
|
|
20
|
+
.gsub('<<field>>', field.to_s.gsub('_', ' '))
|
|
21
|
+
# TODO: SanitizationService for things like ^
|
|
22
|
+
|
|
23
|
+
TemplateService.perform_data_replacements(template, content)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.field_type value
|
|
27
|
+
# TODO: piggyback on Watson NLC
|
|
28
|
+
puts "Looking at [#{value.inspect}]"
|
|
29
|
+
case value
|
|
30
|
+
when :best_friend, :mother
|
|
31
|
+
'Character'
|
|
32
|
+
else
|
|
33
|
+
'Data'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# TODO: stick this in internationalized yaml
|
|
38
|
+
# TODO: make this smarter
|
|
39
|
+
def self.questions_for type
|
|
40
|
+
case type
|
|
41
|
+
when 'Character'
|
|
42
|
+
[
|
|
43
|
+
# e.g. field=best_friend -> "Who is Alice's best friend?"
|
|
44
|
+
"Who is [[title]]'s <<field>>?"
|
|
45
|
+
]
|
|
46
|
+
when 'Location'
|
|
47
|
+
[
|
|
48
|
+
# e.g. field=hometown -> "Where is Alice's home town?"
|
|
49
|
+
"Where is [[title]]'s <<field>>?"
|
|
50
|
+
]
|
|
51
|
+
when 'Item'
|
|
52
|
+
[
|
|
53
|
+
# e.g. field=favorite_item -> "What is Alice's favorite item?"
|
|
54
|
+
"What is [[title]]'s <<field>>?"
|
|
55
|
+
]
|
|
56
|
+
when 'Data'
|
|
57
|
+
[
|
|
58
|
+
# e.g. field=height -> "What is Alice's height?"
|
|
59
|
+
# TODO: special cases here:
|
|
60
|
+
# height -> "How tall is..."
|
|
61
|
+
# weight -> "How much does...weigh?"
|
|
62
|
+
# age -> "How old is..."
|
|
63
|
+
"What is [[title]]'s <<field>>?"
|
|
64
|
+
]
|
|
65
|
+
else
|
|
66
|
+
[
|
|
67
|
+
'Dunno lol'
|
|
68
|
+
]
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# TODO: scope this class (and all other classes) into Serendipity:: namespace
|
|
2
|
+
# TODO: ExternalDataLayer to base suggestions on real-world stats provided
|
|
3
|
+
# elsewhere
|
|
4
|
+
|
|
5
|
+
# Looks at a piece of content and makes a suggestion on improving it
|
|
6
|
+
class SuggestionService
|
|
7
|
+
def self.suggestion(content)
|
|
8
|
+
"What is #{content}?"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Template service
|
|
2
|
+
class TemplateService
|
|
3
|
+
# Regex to determine whether a word is in template replacement format
|
|
4
|
+
# e.g. [[user.name]] or [[day_of_week]]
|
|
5
|
+
TOKEN_REGEX = /\[\[([^\]]+)\]\]/
|
|
6
|
+
# TODO: Support nested template replacement [[e.g. another_user.title]] instead of [[title]]
|
|
7
|
+
|
|
8
|
+
# Regex to find symbolic reductions
|
|
9
|
+
SRAI_REGEX = /<<([^>]+)>>/
|
|
10
|
+
# TODO: implement symbolic reductions
|
|
11
|
+
|
|
12
|
+
def self.perform_data_replacements template, content
|
|
13
|
+
template.gsub(TOKEN_REGEX) do |token|
|
|
14
|
+
replacement_for(remove_brackets(token), content)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.perform_symbolic_reductions template
|
|
19
|
+
# template.gsub(SRAI_REGEX) do |srai|
|
|
20
|
+
# reduction_template = KeywordMatcherService.match_to_template srai
|
|
21
|
+
# replaced_template = TemplateReplacerService.replace_replacements reduction_template
|
|
22
|
+
|
|
23
|
+
# replaced_template
|
|
24
|
+
# end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.replacement_for token, content
|
|
28
|
+
# TODO: not this
|
|
29
|
+
content.send token
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def self.remove_brackets(token)
|
|
35
|
+
token.sub(/^\[\[/, '')
|
|
36
|
+
.sub(/\]\]$/, '')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'serendipitous/content'
|
|
2
|
+
|
|
3
|
+
require 'serendipitous/question_service'
|
|
4
|
+
require 'serendipitous/suggestion_service'
|
|
5
|
+
require 'serendipitous/prompt_service'
|
|
6
|
+
require 'serendipitous/content_service'
|
|
7
|
+
require 'serendipitous/template_service'
|
|
8
|
+
|
|
9
|
+
# Gem interface
|
|
10
|
+
class Serendipitous
|
|
11
|
+
def self.question(content)
|
|
12
|
+
QuestionService.question(content)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.suggestion(_content)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.prompt(_content)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# maybe
|
|
22
|
+
# def self.problems content
|
|
23
|
+
# end
|
|
24
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: serendipitous
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andrew Brown
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-04-20 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: An engine for creative feedback
|
|
14
|
+
email: andrew@indentlabs.com
|
|
15
|
+
executables: []
|
|
16
|
+
extensions: []
|
|
17
|
+
extra_rdoc_files: []
|
|
18
|
+
files:
|
|
19
|
+
- lib/serendipitous.rb
|
|
20
|
+
- lib/serendipitous/content.rb
|
|
21
|
+
- lib/serendipitous/content_service.rb
|
|
22
|
+
- lib/serendipitous/prompt_service.rb
|
|
23
|
+
- lib/serendipitous/question_service.rb
|
|
24
|
+
- lib/serendipitous/suggestion_service.rb
|
|
25
|
+
- lib/serendipitous/template_service.rb
|
|
26
|
+
homepage: http://indentlabs.com/serendipitous
|
|
27
|
+
licenses:
|
|
28
|
+
- MIT
|
|
29
|
+
metadata: {}
|
|
30
|
+
post_install_message:
|
|
31
|
+
rdoc_options: []
|
|
32
|
+
require_paths:
|
|
33
|
+
- lib
|
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '0'
|
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0'
|
|
44
|
+
requirements: []
|
|
45
|
+
rubyforge_project:
|
|
46
|
+
rubygems_version: 2.4.5.1
|
|
47
|
+
signing_key:
|
|
48
|
+
specification_version: 4
|
|
49
|
+
summary: Creative query engine
|
|
50
|
+
test_files: []
|