aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToshiaki Asai <toshi.alternative@gmail.com>2016-10-22 18:55:04 +0900
committerToshiaki Asai <toshi.alternative@gmail.com>2016-10-22 19:29:47 +0900
commit5a56709b4be80f6d8bc4c87795dc609416b8bb72 (patch)
tree04d2b159ea31386bcf88bbe221a52204e924b174
parent2afae5e4671d307195b8d622d870e485bc6e5f9c (diff)
downloadmikutter-5a56709b4be80f6d8bc4c87795dc609416b8bb72.tar.gz
次のintentで開く refs #906
-rw-r--r--core/plugin/intent/intent.rb53
-rw-r--r--core/plugin/intent/model/intent_token.rb31
2 files changed, 70 insertions, 14 deletions
diff --git a/core/plugin/intent/intent.rb b/core/plugin/intent/intent.rb
index 12cc69fc..4d3d9bf6 100644
--- a/core/plugin/intent/intent.rb
+++ b/core/plugin/intent/intent.rb
@@ -20,6 +20,11 @@ Plugin.create(:intent) do
defevent :intent_select,
prototype: [Enumerable, tcor(URI, String, Retriever::Model)]
+ # IntentTokenの次にあたるintentを発生させる。
+ defevent :intent_forward,
+ priority: :ui_response,
+ prototype: [Plugin::Intent::IntentToken]
+
# _model_ を開く方法を新しく登録する。
# ==== Args
# [model] サポートするModelのClass
@@ -63,30 +68,43 @@ Plugin.create(:intent) do
end
end
+ on_intent_forward do |intent_token|
+ case intent_token[:source]
+ when Retriever::Model
+ open_model(intent_token[:source], token: intent_token)
+ else
+ open_uri(intent_token.uri, token: intent_token)
+ end
+ end
+
# _uri_ をUI上で開く。
# このメソッドが呼ばれたらIntentTokenを生成して、開くことを試みる。
# open_modelのほうが高速なので、modelオブジェクトが存在するならばopen_modelを呼ぶこと。
# ==== Args
# [uri] 対象となるURI
- def open_uri(uri)
+ # [token:] 親となるIntentToken
+ def open_uri(uri, token: nil)
model_slugs = Plugin.filtering(:model_of_uri, uri.freeze, Set.new).last
if model_slugs.empty?
error "model not found to open for #{uri}"
return
end
- intents = model_slugs.inject(Set.new) do |memo, model_slug|
- memo.merge(Plugin.filtering(:intent_select_by_model_slug, model_slug, Set.new).last)
+ intents = model_slugs.lazy.flat_map{|model_slug|
+ Plugin.filtering(:intent_select_by_model_slug, model_slug, []).last
+ }
+ if token
+ intents = intents.reject{|intent| token.intent_ancestors.include?(intent) }
end
- if intents.empty?
+ head = intents.first(2)
+ case head.size
+ when 0
error "intent not found to open for #{model_slugs.to_a}"
return
- end
- if intents.size == 1
- intent = intents.to_a.first
+ when 1
Plugin::Intent::IntentToken.open(
uri: uri,
- intent: intent,
- parent: nil)
+ intent: head.first,
+ parent: token)
else
Plugin.call(:intent_select, intents, uri)
end
@@ -98,16 +116,23 @@ Plugin.create(:intent) do
# このメソッドはヒントとして _model_ を与えるため、探索が発生せず高速に処理できる。
# ==== Args
# [model] 対象となるRetriever::Model
- def open_model(model)
+ def open_model(model, token: nil)
intents = Plugin.filtering(:intent_select_by_model_slug, model.class.slug, Set.new).last
- # TODO: intents をユーザに選択させる
- if intents.size == 1
- intent = intents.to_a.first
+ if token
+ intents = intents.reject{|intent| token.intent_ancestors.include?(intent) }
+ end
+ head = intents.first(2)
+ case head.size
+ when 0
+ type_strict model.uri => URI
+ open_uri(model.uri, token: token)
+ when 1
+ intent = head.first
Plugin::Intent::IntentToken.open(
uri: model.uri,
model: model,
intent: intent,
- parent: nil)
+ parent: token)
else
Plugin.call(:intent_select, intents, model)
end
diff --git a/core/plugin/intent/model/intent_token.rb b/core/plugin/intent/model/intent_token.rb
index 2279c0ce..cd14286f 100644
--- a/core/plugin/intent/model/intent_token.rb
+++ b/core/plugin/intent/model/intent_token.rb
@@ -5,12 +5,18 @@ module Plugin::Intent
field.string :uri, required: true
field.has :model, Retriever::Model
field.has :intent, Plugin::Intent::Intent, required: true
+ field.has :parent, Plugin::Intent::IntentToken
# 引数の情報からIntentTokenを作成し、それを開く
def self.open(*args)
self.new(*args).open
end
+ def initialize(*rest)
+ super
+ self[:source] = self[:model]
+ end
+
# 設定された情報を使ってURI又はModelを開く
def open
if model?
@@ -25,5 +31,30 @@ module Plugin::Intent
end
self
end
+
+ def forward
+ Plugin.call(:intent_forward, self)
+ end
+
+ # _self_ から親のIntentTokenを再帰的に遡って、そのIntentTokenを引数に繰り返すEnumeratorを返す。
+ # ==== Return
+ # [Enumerator] IntentTokenを列挙する
+ def ancestors
+ Enumerator.new do |yielder|
+ cur = self
+ loop do
+ break unless cur
+ yielder << cur
+ cur = cur.parent
+ end
+ end
+ end
+
+ # ancestorsと同じようなもの。ただし、IntentToken#intentに関して繰り返す。
+ # ==== Return
+ # [Enumerator] Intentを列挙する
+ def intent_ancestors
+ ancestors.lazy.map(&:intent)
+ end
end
end