smartdict-core 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.
Files changed (50) hide show
  1. data/README.markdown +77 -0
  2. data/bin/smartdict +20 -0
  3. data/bin/smartdict-populator +50 -0
  4. data/config/default_config.yml +15 -0
  5. data/lib/smartdict/commands/abstract_command.rb +225 -0
  6. data/lib/smartdict/commands/has_format_list.rb +28 -0
  7. data/lib/smartdict/commands/help_command.rb +53 -0
  8. data/lib/smartdict/commands/list_command.rb +45 -0
  9. data/lib/smartdict/commands/translate_command.rb +35 -0
  10. data/lib/smartdict/commands.rb +10 -0
  11. data/lib/smartdict/core/command_manager.rb +27 -0
  12. data/lib/smartdict/core/driver_manager.rb +9 -0
  13. data/lib/smartdict/core/format_manager.rb +8 -0
  14. data/lib/smartdict/core/has_logger.rb +12 -0
  15. data/lib/smartdict/core/is_manager.rb +21 -0
  16. data/lib/smartdict/core/logger.rb +5 -0
  17. data/lib/smartdict/core/plugin_manager.rb +32 -0
  18. data/lib/smartdict/core.rb +12 -0
  19. data/lib/smartdict/drivers/abstract_driver.rb +61 -0
  20. data/lib/smartdict/drivers/google_translate_driver.rb +56 -0
  21. data/lib/smartdict/drivers.rb +6 -0
  22. data/lib/smartdict/errors.rb +11 -0
  23. data/lib/smartdict/formats/abstract_format.rb +21 -0
  24. data/lib/smartdict/formats/fb2_format.rb +40 -0
  25. data/lib/smartdict/formats/text_color_format.rb +52 -0
  26. data/lib/smartdict/formats/text_format.rb +9 -0
  27. data/lib/smartdict/formats.rb +8 -0
  28. data/lib/smartdict/list_builder.rb +51 -0
  29. data/lib/smartdict/models/driver.rb +14 -0
  30. data/lib/smartdict/models/language.rb +16 -0
  31. data/lib/smartdict/models/translated_word.rb +14 -0
  32. data/lib/smartdict/models/translation.rb +83 -0
  33. data/lib/smartdict/models/translation_query.rb +13 -0
  34. data/lib/smartdict/models/word.rb +13 -0
  35. data/lib/smartdict/models/word_class.rb +14 -0
  36. data/lib/smartdict/models.rb +11 -0
  37. data/lib/smartdict/plugin/initializer_context.rb +7 -0
  38. data/lib/smartdict/plugin.rb +9 -0
  39. data/lib/smartdict/runner.rb +5 -0
  40. data/lib/smartdict/storage/seeder.rb +32 -0
  41. data/lib/smartdict/storage/seeds/drivers.csv +2 -0
  42. data/lib/smartdict/storage/seeds/languages.csv +188 -0
  43. data/lib/smartdict/storage/seeds/word_classes.csv +10 -0
  44. data/lib/smartdict/storage.rb +44 -0
  45. data/lib/smartdict/translation.rb +19 -0
  46. data/lib/smartdict/translator.rb +38 -0
  47. data/lib/smartdict/version.rb +3 -0
  48. data/lib/smartdict-core.rb +1 -0
  49. data/lib/smartdict.rb +97 -0
  50. metadata +468 -0
data/README.markdown ADDED
@@ -0,0 +1,77 @@
1
+ # Smartdict
2
+
3
+ Simple dictionary.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ gem install smartdict
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ To get help just type:
14
+
15
+ ```
16
+ smartdict --help
17
+ ```
18
+
19
+ To get a help on specific command:
20
+
21
+ ```
22
+ smartdict help <COMMAND>
23
+ ```
24
+
25
+ ### Translate words:
26
+
27
+ To translate word `hallo` from German to Russian:
28
+
29
+ smartdict translate --from de --to ru hallo
30
+
31
+
32
+ ### List translated words:
33
+
34
+ If you want to take a look at words you've translated use `list` command.
35
+ You can specify date range and languages to filter words and
36
+ you can specify format for output.
37
+
38
+ To get more information see help:
39
+
40
+ ```
41
+ smartdict translate --help
42
+ ```
43
+
44
+ #### Example:
45
+
46
+ To see words translated today:
47
+
48
+ ```
49
+ smartdict list
50
+ ```
51
+
52
+ To save words translated since 13th of January 2012 from English to Russian in
53
+ [FictionBook](http://en.wikipedia.org/wiki/FictionBook) format to `words.fb2`
54
+ file.
55
+
56
+
57
+ ```
58
+ smartdict --since 2012-01-13 --from en --to ru --format fb2 > ./words.fb2
59
+ ```
60
+
61
+ ## How to configure?
62
+
63
+ See file `$HOME/.smartdict/configuration.yml`.
64
+
65
+ NOTE: currently not all options listed there have an effect.
66
+
67
+
68
+ ## Contributing to smartdict
69
+
70
+ * Make sure all tests pass.
71
+ * Send me a patch.
72
+
73
+ ## Copyright
74
+
75
+ Copyright (c) 2012 Potapov Sergey. The software is distributed under
76
+ [GNU GeneralPublic License version 2](http://www.gnu.org/licenses/gpl-2.0.txt).
77
+ See GPL-LICENSE.txt file for more details.
data/bin/smartdict ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+ require 'rubygems'
5
+
6
+ require 'smartdict'
7
+ require 'smartdict/runner'
8
+
9
+ # TODO: remove before release
10
+ # require 'pry'
11
+
12
+ Smartdict.env = :user
13
+
14
+ args = ARGV.clone
15
+
16
+ Smartdict.load_plugins
17
+
18
+ # TODO :move Smartdict.run to Runner.run
19
+ Smartdict.run
20
+ Smartdict::Runner.run(args)
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+ require 'rubygems'
5
+
6
+ require 'smartdict'
7
+ require 'smartdict/runner'
8
+
9
+ Smartdict.env = :user
10
+
11
+ args = ARGV.clone
12
+
13
+ Smartdict.load_plugins
14
+
15
+ # TODO :mode Smartdict.run to Runner.run
16
+ Smartdict.run
17
+
18
+
19
+
20
+ def translate(word)
21
+ Smartdict::Translator.translate(word)
22
+ rescue Smartdict::TranslationNotFound
23
+ end
24
+
25
+ def translate_words(words, from_lang, to_lang)
26
+ words.each_with_index do |word, index|
27
+ translate word
28
+ if index % 10 == 0
29
+ print "#{index}/#{words.size} = %2.2f%" % [index.to_f/words.size * 100]
30
+ puts " #{from_lang.name} -> #{to_lang.name}"
31
+ end
32
+ end
33
+ end
34
+
35
+ from_lang = Smartdict::Models::Language.first(:code => 'en')
36
+ to_lang = Smartdict::Models::Language.first(:code => 'ru')
37
+
38
+
39
+ while(true)
40
+ Smartdict::Translator.from_lang_code = from_lang.code
41
+ Smartdict::Translator.to_lang_code = to_lang.code
42
+
43
+ words = Smartdict::Models::Word.all(:language_id => from_lang.id).map(&:name)
44
+ translate_words(words, from_lang, to_lang)
45
+
46
+ from_lang, to_lang = to_lang, from_lang
47
+ end
48
+
49
+
50
+
@@ -0,0 +1,15 @@
1
+ plugins:
2
+
3
+ store:
4
+ adapter: sqlite
5
+
6
+ default:
7
+ from_lang: en
8
+ to_lang: ru
9
+ format: text_color
10
+ langs:
11
+ - en
12
+ - ru
13
+ - de
14
+ - es
15
+ - fr
@@ -0,0 +1,225 @@
1
+ # Basic class for all command classes.
2
+ #
3
+ # == Usage:
4
+ # class Smartdict::Commands::HelloCommand < Smartdict::Commands::AbstractCommand
5
+ # # arguments and their default values
6
+ # arguments :name
7
+ # default :name => "world"
8
+ #
9
+ # # options and their default values.
10
+ # options :greating => "Hello",
11
+ # :today => lambda { Time.now.strftime("%A") }
12
+ #
13
+ # # Other helpful information about the command
14
+ # set_name "hello"
15
+ # set_summary "Summary for the hello command"
16
+ # set_description "Demonstrates how Command class works"
17
+ # set_syntax "#{prog_name} NAME [--greating GREATING] [--today DAY]"
18
+ # set_usage <<-USAGE
19
+ # #{prog_name}
20
+ # #{prog_name} Sergey
21
+ # #{prog_name} --today Friday
22
+ # USAGE
23
+ #
24
+ # # This method runs when command executes.
25
+ # def execute
26
+ # puts "#{@options[:greating]} #{@arguments[:name]}! Today is #{@options[:today]}."
27
+ # end
28
+ # end
29
+ #
30
+ # # == Output:
31
+ # # smartdict hello
32
+ # # Hello world! Today is Monday.
33
+ # #
34
+ # # smartdict hello Sergey
35
+ # # Hello Sergey! Today is Monday.
36
+ # #
37
+ # # smartdict hello Sergey --today Friday
38
+ # # Hello Sergey! Today is Friday.
39
+ class Smartdict::Commands::AbstractCommand
40
+ # Number of spaces for indent.
41
+ INDENT_SIZE = 2
42
+
43
+ # array with available arguments
44
+ class_attribute :known_arguments
45
+
46
+ # hash with default values for {known_arguments}.
47
+ class_attribute :default_argument_values
48
+
49
+ # hash with names of options and default values
50
+ class_attribute :known_options
51
+
52
+ # short summary message for a command
53
+ class_attribute :summary
54
+
55
+ # command description
56
+ class_attribute :description
57
+
58
+ # command name
59
+ class_attribute :name
60
+
61
+ # multi line text with syntax format
62
+ class_attribute :syntax
63
+
64
+ # multi line text with usage example
65
+ class_attribute :usage
66
+
67
+ # Runs command.
68
+ # @param [Array] args arguments passed from the command line
69
+ def self.run(args)
70
+ if ['--help', '-h'].include?(args.first)
71
+ puts help_message
72
+ else
73
+ self.new(args).execute
74
+ end
75
+ rescue Smartdict::Error => err
76
+ puts err.message
77
+ end
78
+
79
+ # Defines available arguments and their order.
80
+ def self.arguments(*argument_names)
81
+ self.known_arguments = argument_names
82
+ end
83
+
84
+ # Sets default values for arguments.
85
+ # @param [Hash] values
86
+ def self.default(values)
87
+ self.default_argument_values = values
88
+ end
89
+
90
+ # Defines available options with their default values.
91
+ # == Usage:
92
+ # options :to => "en",
93
+ # :from => lambda { Settings.current_language }
94
+ def self.options(options = {})
95
+ raise Smartdict::Error.new("options must be a hash") unless options.is_a? Hash
96
+ self.known_options = options
97
+ end
98
+
99
+ # Sets summary message for a command.
100
+ def self.set_summary(summary)
101
+ self.summary = summary
102
+ end
103
+
104
+ # Sets description message for a command.
105
+ def self.set_description(description)
106
+ self.description = description
107
+ end
108
+
109
+ # Defines name of a command.
110
+ def self.set_name(name)
111
+ self.name = name
112
+ end
113
+
114
+ # Sets syntax message.
115
+ # @param [String] syntax multi line text with number of syntax examples
116
+ def self.set_syntax(syntax)
117
+ self.syntax = syntax
118
+ end
119
+
120
+ # Sets usage examples
121
+ # @param [String] usage multi line text with number of usage examples.
122
+ def self.set_usage(usage)
123
+ self.usage = usage
124
+ end
125
+
126
+ # @return [String] program name. It's meant to be used in usage examples.
127
+ def self.prog_name
128
+ "smartdict #{name}"
129
+ end
130
+
131
+ # @return [String] help message for the command to be displayed.
132
+ def self.help_message
133
+ message = "#{description}\n\n"
134
+ message << "#{help_syntax_message}\n"
135
+ message << "#{help_usage_message}\n"
136
+ end
137
+
138
+ # @return [String] syntax part of the help message.
139
+ def self.help_syntax_message
140
+ result = " " * INDENT_SIZE + "Syntax:\n"
141
+ syntax.split("\n").map do |line|
142
+ result << " " * INDENT_SIZE * 2 + "#{line.strip}\n"
143
+ end
144
+ result
145
+ end
146
+
147
+ # @return [String] usage part of the help message.
148
+ def self.help_usage_message
149
+ result = " " * INDENT_SIZE + "Usage:\n"
150
+ usage.split("\n").map do |line|
151
+ result << " " * INDENT_SIZE * 2 + "#{line.strip}\n"
152
+ end
153
+ result
154
+ end
155
+
156
+ # Sets default values for class attributes.
157
+ def self.inherited(base)
158
+ base.known_arguments ||= []
159
+ base.default_argument_values ||= {}
160
+ base.known_options ||= {}
161
+ end
162
+
163
+
164
+
165
+ # @param [Array] args arguments passed from the command line
166
+ def initialize(args = [])
167
+ set_arguments_and_options!(args)
168
+ end
169
+
170
+ # Parses all passed arguments and initializes @arguments and @options variables.
171
+ # @param [Array] args arguments passed from the command line
172
+ def set_arguments_and_options!(args)
173
+ arguments, options = extract_arguments_and_options(args)
174
+ set_arguments!(arguments)
175
+ set_options!(options)
176
+ end
177
+
178
+ # Splits input args to arguments and options.
179
+ # Returns arguments as an array and options as a hash.
180
+ def extract_arguments_and_options(args)
181
+ arguments = []
182
+ options = {}
183
+ args = args.dup
184
+ while value = args.shift
185
+ if match = value.match(/^--(\w+)/)
186
+ options[match[1].to_sym] = args.shift
187
+ else
188
+ arguments << value
189
+ end
190
+ end
191
+ [arguments, options]
192
+ end
193
+
194
+ # Initializes @arguments variable.
195
+ # If no argument was passed then it uses default value.
196
+ def set_arguments!(arg_values)
197
+ @arguments = {}
198
+ known_arguments.each_with_index do |arg_name, index|
199
+ if value = arg_values[index]
200
+ @arguments[arg_name.to_sym] = value
201
+ elsif default_argument_values.has_key?(arg_name.to_sym)
202
+ @arguments[arg_name.to_sym] = default_argument_values[arg_name.to_sym]
203
+ else
204
+ raise Smartdict::Error.new("Argument `#{arg_name}` is not passed")
205
+ end
206
+ end
207
+ end
208
+
209
+ # Initializes @options variable.
210
+ # If no argument was passed then it uses default value.
211
+ def set_options!(options)
212
+ @options = {}
213
+ known_options.each do |opt_name, default_value|
214
+ value = options[opt_name]
215
+ unless value
216
+ value = case default_value
217
+ when Proc then default_value.call
218
+ else default_value
219
+ end
220
+ end
221
+ @options[opt_name] = value
222
+ end
223
+ end
224
+
225
+ end
@@ -0,0 +1,28 @@
1
+ # Extends {help_message} method to provide list of formats.
2
+ module Smartdict::Commands::HasFormatList
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.class_eval do
6
+ class << self
7
+ alias_method_chain :help_message, :formats
8
+ end
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ def help_message_with_formats
14
+ formats = Smartdict::Core::FormatManager.all
15
+ width = formats.values.map{|f| f.name.size}.max
16
+ indent = Smartdict::Commands::AbstractCommand::INDENT_SIZE
17
+
18
+ message = " " * indent + "Formats:\n"
19
+ formats.each do |name, format|
20
+ message << " " * 2 * indent
21
+ message << name.ljust(width) + " "
22
+ message << "#{format.description}\n"
23
+ end
24
+
25
+ help_message_without_formats << message
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,53 @@
1
+ module Smartdict::Commands
2
+ class HelpCommand < AbstractCommand
3
+ include Smartdict::Core
4
+
5
+ arguments :command
6
+ default :command => nil
7
+
8
+ set_name "help"
9
+ set_summary "Show help message"
10
+ set_description "Smartdict is a dictionary designed to improve you knowledge of foreign languages."
11
+ set_syntax <<-SYNTAX
12
+ smartdict COMMAND [arguments...] [options...]
13
+ #{prog_name} COMMAND
14
+ smartdict --help
15
+ smartdict --version
16
+ SYNTAX
17
+
18
+ set_usage <<-SYNTAX
19
+ #{prog_name} translate
20
+ #{prog_name} list
21
+ SYNTAX
22
+
23
+ def execute
24
+ if cmd_name = @arguments[:command]
25
+ if cmd_class = CommandManager.find(cmd_name)
26
+ puts cmd_class.help_message
27
+ else
28
+ abort "Uknown command: #{cmd_name}"
29
+ end
30
+ else
31
+ puts help_message
32
+ end
33
+ end
34
+
35
+ def help_message
36
+ message = "#{description}\n\n"
37
+ message << "#{self.class.help_syntax_message}\n"
38
+ message << help_commands_message
39
+ end
40
+
41
+
42
+ def help_commands_message
43
+ width = CommandManager.all.keys.map(&:size).max
44
+ result = " " * INDENT_SIZE + "Commands:\n"
45
+ CommandManager.all.each do |command_name, command_class|
46
+ result << " " * 2 * INDENT_SIZE + "#{command_name.ljust(width)}"
47
+ result << " #{command_class.summary}\n"
48
+ end
49
+ result
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,45 @@
1
+ module Smartdict::Commands
2
+ class ListCommand < AbstractCommand
3
+ include HasFormatList
4
+ include Smartdict::Models
5
+
6
+ set_name "list"
7
+ set_summary "Lists words you translated before"
8
+ set_description "Lists words you translated before in selected format(text_color by default)."
9
+ set_syntax <<-SYNTAX
10
+ #{prog_name} [--since DATE] [--till DATE] [--format FORMAT] [--from LANG] [--to LANG]
11
+ SYNTAX
12
+
13
+ set_usage <<-SYNTAX
14
+ #{prog_name}
15
+ #{prog_name} --since 2012-02-14 --till 2012-02-21
16
+ #{prog_name} --from de --to en --format text
17
+ SYNTAX
18
+
19
+ options :format => lambda { configatron.default.format },
20
+ :since => lambda { Date.today },
21
+ :till => lambda { Time.now },
22
+ :from => nil,
23
+ :to => nil,
24
+ :driver => nil
25
+
26
+ def execute
27
+ list_opts = {
28
+ :since => @options[:since],
29
+ :till => @options[:till],
30
+ :from_lang => @options[:from],
31
+ :to_lang => @options[:to],
32
+ :driver => @options[:driver]
33
+ }
34
+ translations = Smartdict::ListBuilder.build(list_opts)
35
+ puts format.format_list(translations)
36
+ end
37
+
38
+ def format
39
+ format = Smartdict::FormatManager.find(@options[:format])
40
+ raise Smartdict::Error.new("Wrong format: #{@options[:format]}") unless format
41
+ format
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,35 @@
1
+ module Smartdict::Commands
2
+ class TranslateCommand < AbstractCommand
3
+ include HasFormatList
4
+
5
+ set_name "translate"
6
+ set_summary "Translate a word"
7
+ set_description "Translate a word"
8
+ set_syntax "#{prog_name} <WORD> [--from LANGUAGE] [--to LANGUAGE] [--format FORMAT]"
9
+ set_usage <<-USAGE
10
+ #{prog_name} hello
11
+ #{prog_name} again --from en --to ru
12
+ #{prog_name} again --format text
13
+ USAGE
14
+
15
+ arguments :word
16
+
17
+ options :from => lambda { configatron.default.from_lang },
18
+ :to => lambda { configatron.default.to_lang },
19
+ :format => lambda { configatron.default.format }
20
+
21
+ def execute
22
+ Smartdict::Translator.from_lang_code = @options[:from]
23
+ Smartdict::Translator.to_lang_code = @options[:to]
24
+ translation = Smartdict::Translator.translate(@arguments[:word])
25
+ puts format.format_translation(translation)
26
+ end
27
+
28
+ def format
29
+ format = Smartdict::FormatManager.find(@options[:format])
30
+ raise Smartdict::Error.new("Wrong format: #{@options[:format]}") unless format
31
+ format
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,10 @@
1
+ module Smartdict::Commands
2
+ extend ActiveSupport::Autoload
3
+
4
+ autoload :AbstractCommand
5
+ autoload :HelpCommand
6
+ autoload :TranslateCommand
7
+ autoload :ListCommand
8
+
9
+ autoload :HasFormatList
10
+ end
@@ -0,0 +1,27 @@
1
+ class Smartdict::Core::CommandManager
2
+ include Smartdict::Core::IsManager
3
+ include Smartdict::Commands
4
+
5
+ register 'help' , HelpCommand
6
+ register 'translate', TranslateCommand
7
+ register 'list' , ListCommand
8
+
9
+
10
+ def self.run(args)
11
+ first_arg = args.shift
12
+ case first_arg
13
+ when nil, '-h', '--help', 'help'
14
+ run_command :help, args
15
+ else
16
+ run_command(first_arg, args)
17
+ end
18
+ end
19
+
20
+ def self.run_command(name, args = [])
21
+ if command = find(name)
22
+ command.run(args)
23
+ else
24
+ abort "Unknown command: #{name}"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ # Managers {Smartdict::Driver translation drivers}.
2
+ # Similar to {Smartdict::Core::CommandManager} it registers drivers
3
+ # and provides interfaces to find them by name.
4
+ class Smartdict::Core::DriverManager
5
+ include Smartdict::Core::IsManager
6
+ include Smartdict::Drivers
7
+
8
+ register 'google_translate', GoogleTranslateDriver
9
+ end
@@ -0,0 +1,8 @@
1
+ class Smartdict::Core::FormatManager
2
+ include Smartdict::Formats
3
+ include Smartdict::Core::IsManager
4
+
5
+ register "text" , TextFormat
6
+ register "text_color", TextColorFormat
7
+ register "fb2" , Fb2Format
8
+ end
@@ -0,0 +1,12 @@
1
+ module Smartdict::Core::HasLogger
2
+ def self.included(base)
3
+ base.extend Methods
4
+ base.send :include, Methods
5
+ end
6
+
7
+ module Methods
8
+ def logger
9
+ Smartdict::Core::Logger.root_logger
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ module Smartdict::Core::IsManager
2
+ def self.included(receiver)
3
+ receiver.instance_variable_set("@entities", {})
4
+ receiver.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def register(name, klass)
9
+ raise Smartdict::Error.new("`#{name}` is already registered") if find(name)
10
+ @entities[name.to_s] = klass
11
+ end
12
+
13
+ def find(name)
14
+ @entities[name.to_s]
15
+ end
16
+
17
+ def all
18
+ @entities
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ class Smartdict::Core::Logger < ::Logger
2
+ def self.root_logger
3
+ @logger ||= self.new(Smartdict.log_path)
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ class Smartdict::Core::PluginManager
2
+ include Smartdict::Core::IsManager
3
+
4
+ def self.load_plugins
5
+ require_plugins
6
+ run_initializers
7
+ end
8
+
9
+
10
+ private
11
+
12
+ def self.require_plugins
13
+ Dir["#{Smartdict.plugins_dir}/*"].each do |plugin_dir|
14
+ plugin_name = File.basename plugin_dir
15
+ require_plugin(plugin_name)
16
+ end
17
+ end
18
+
19
+ def self.require_plugin(plugin_name)
20
+ $LOAD_PATH << "#{Smartdict.plugins_dir}/#{plugin_name}/lib"
21
+ require plugin_name
22
+ rescue LoadError
23
+ log.error "Can't load plugin `#{plugin_name}` from directory #{Smartdict.plugins_dir}"
24
+ $LOAD_PATH.pop
25
+ end
26
+
27
+ def self.run_initializers
28
+ all.each do |name, data|
29
+ Smartdict::Plugin::InitializerContext.new.instance_eval &data[:block]
30
+ end
31
+ end
32
+ end