1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
# -*- coding: utf-8 -*-
miquire :core, "miquire", "plugin", "miquire_to_spec"
# プラグインのロードに関すること
module Miquire::Plugin
class << self
using Miquire::ToSpec
include Enumerable
# ロードパスの配列を返す。
# ロードパスに追加したい場合は、以下のようにすればいい
#
# Miquire::Plugin.loadpath << 'pathA' << 'pathB'
def loadpath
@loadpath ||= [] end
# プラグインのファイル名(フルパス)で繰り返す。
def each
iterated = Set.new
detected = []
loadpath.reverse.each { |path|
Dir[File.join(File.expand_path(path), '*')].each { |file|
if FileTest.directory?(file) and FileTest.exist?(File.join(file, File.basename(file))+'.rb')
file = File.join(file, File.basename(file))+'.rb'
elsif not file.end_with?('.rb'.freeze)
next end
plugin_name = File.basename(file, '.rb')
if not iterated.include? plugin_name
iterated << plugin_name
detected << file end } }
detected.sort_by{ |a|
[:bundle == get_kind(a) ? 0 : 1, a]
}.each(&Proc.new) end
def each_spec
each{ |path|
spec = get_spec path
yield spec if spec } end
def to_hash
result = {}
each_spec{ |spec|
result[spec[:slug]] = spec }
result end
# 受け取ったパスにあるプラグインのスラッグを返す
# ==== Args
# [path] パス(String)
# ==== Return
# プラグインスラッグ(Symbol)
def get_slug(path)
type_strict path => String
spec = get_spec(path)
if spec
spec[:slug]
else
File.basename(path, ".rb").to_sym end end
# specファイルがあればそれを返す
# ==== Args
# [path] パス(String)
# ==== Return
# specファイルの内容か、存在しなければnil
def get_spec(path)
type_strict path => String
plugin_dir = FileTest.directory?(path) ? path : File.dirname(path)
spec_filename = File.join(plugin_dir, ".mikutter.yml")
deprecated_spec = false
unless FileTest.exist? spec_filename
spec_filename = File.join(plugin_dir, "spec")
deprecated_spec = true end
if FileTest.exist? spec_filename
YAML.load_file(spec_filename).symbolize
.merge(kind: get_kind(path),
path: plugin_dir,
deprecated_spec: deprecated_spec)
elsif FileTest.exist? path
{ slug: File.basename(path, ".rb").to_sym,
kind: get_kind(path),
path: plugin_dir,
deprecated_spec: false } end end
def get_spec_by_slug(slug)
type_strict slug => Symbol
to_hash[slug] end
# プラグインがthirdpartyかbundleかを返す
def get_kind(path)
type_strict path => String
if path.start_with?(Environment::PLUGIN_PATH)
:bundle
else
:thirdparty end end
def load_all
each_spec{ |spec|
begin
load spec
rescue Miquire::LoadError => e
::Plugin.call(:modify_activity,
kind: "system",
title: "#{spec[:slug]} load failed",
date: Time.new,
exception: e,
description: e.to_s) end } end
def satisfy_mikutter_version?(spec)
if defined?(spec[:depends][:mikutter]) and spec[:depends][:mikutter]
version = Environment::Version.new(*(spec[:depends][:mikutter].split(".").map(&:to_i) + ([0]*4))[0...4])
if Environment::VERSION < version
raise Miquire::LoadError, "plugin #{spec[:slug]}: #{Environment::NAME} version too old (#{spec[:depends][:mikutter]} required, but #{Environment::NAME} version is #{Environment::VERSION})"
return false end end
true
end
def depended_plugins(_spec, recursive: false)
spec = _spec.to_spec
unless spec
error "spec #{_spec.inspect}"
return false
end
if defined? spec[:depends][:plugin]
if recursive
local_depends = Array(spec[:depends][:plugin]).map{ |s| Array(s).first.to_sym }
local_depends += local_depends.map {|s|
depended_plugins(s, recursive: recursive).map{|d|d[:slug].to_sym}
}.flatten
local_depends.uniq.map{|d| d.to_spec }
else
Array(spec[:depends][:plugin]).map do |s|
slug = Array(s).first.to_sym
if slug
slug.to_spec
else
slug end end end
else
[] end end
def load(_spec)
return false unless _spec
spec = _spec.to_spec
return false unless spec
return true if ::Plugin.instance_exist?(spec[:slug])
return false unless satisfy_mikutter_version?(spec)
depended_plugins(spec).each do |depend|
begin
raise Miquire::LoadError unless load(depend)
rescue Miquire::LoadError
raise Miquire::LoadError, "plugin #{spec[:slug]}: dependency error: plugin #{depend} was not loaded." end end
notice "plugin loaded: " + File.join(spec[:path], "#{spec[:slug]}.rb")
::Plugin.create(spec[:slug].to_sym) do
self.spec = spec end
Kernel.load File.join(spec[:path], "#{spec[:slug]}.rb")
if spec[:deprecated_spec]
title = "#{spec[:slug]}: specファイルは非推奨になりました。"
Plugin.call(:modify_activity,
{ plugin: spec[:slug],
kind: "error",
title: title,
date: Time.now,
spec: spec,
description: "#{title}\n代わりに.mikutter.ymlを使ってください。"}) end
true end
end
end
|