ducksboard_reporter 0.0.7 → 0.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d7f00fc8b81a969ebe5929f8ad0c425ff83c5db0
4
- data.tar.gz: ba5f182123e40a7631c60c7318c0c7c13cd8daba
3
+ metadata.gz: 2e9e37631f42cbb8f97861aba8f999a1d1f2e9ca
4
+ data.tar.gz: 23adcddf869c5325194a3d86822501437f6213ef
5
5
  SHA512:
6
- metadata.gz: 02447f41db7fcb8fa6f366fd127c9787da9296c61e579575f4e6cdc99399aeb7d991b7e202969641abc24fffabb41359b3b8e6ddf9017745c481ab96bb003b81
7
- data.tar.gz: 7ecd587c9dae113a7663af7e1319829174c9962e433a2e4010501b55e3d811dfe0a05c7c6187f3e6f4a4988d37936cf3a4d39d0422efd5d1d913bbc4a04b3d35
6
+ metadata.gz: 447a3fc6aa73461881fd04aeef2066b2cb060aae83eae61b2d46f2f5be2f8e8dfc43154ac926d9952ea16e085534d60bfc6695a8f832c28dfb314718ba2a8e92
7
+ data.tar.gz: 367a1f301afa96ed6484be68199dd76b52462ca7ba8a4c99683598d3dcd03888c29693b89ee215b25f063a098827323b493640963245d5c2f3ff3ad9a43413ce
@@ -3,10 +3,11 @@ $:.unshift File.expand_path("../../lib", __FILE__)
3
3
 
4
4
  require "ducksboard_reporter"
5
5
  require "trollop"
6
+ require "yaml"
6
7
 
7
8
  opts = Trollop::options do
8
- opt :config_file, "Define config file", short: 'f', type: :string, required: true
9
+ opt :config_file, "Path to config file", short: "f", type: :string, required: true
9
10
  end
10
11
 
11
- DucksboardReporter.config_file = opts[:config_file]
12
- DucksboardReporter.start
12
+ config = YAML.load_file(opts[:config_file])
13
+ DucksboardReporter::App.new(config).start
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
2
+ lib = File.expand_path("../lib", __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'ducksboard_reporter/version'
4
+ require "ducksboard_reporter/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "ducksboard_reporter"
@@ -20,10 +20,13 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.6"
22
22
  spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "fuubar"
25
+ spec.add_development_dependency "byebug"
23
26
 
24
- spec.add_runtime_dependency "ducksboard"
25
- spec.add_runtime_dependency "hashie"
26
- spec.add_runtime_dependency "celluloid"
27
- spec.add_runtime_dependency "timers"
28
- spec.add_runtime_dependency "trollop"
27
+ spec.add_runtime_dependency "ducksboard", "~> 0.1.6"
28
+ spec.add_runtime_dependency "hashie", ">= 3.3.1"
29
+ spec.add_runtime_dependency "celluloid", "~> 0.16"
30
+ spec.add_runtime_dependency "timers", ">= 1.1.0"
31
+ spec.add_runtime_dependency "trollop", ">= 1.16.2"
29
32
  end
data/example_config.yml CHANGED
@@ -7,7 +7,8 @@ reporters:
7
7
 
8
8
  - name: haproxy_log_requests
9
9
  type: HaproxyLogRequests
10
- logfile: /var/log/haproxy.log
10
+ options:
11
+ log_file: /var/log/haproxy.log
11
12
 
12
13
  widgets:
13
14
  - type: Box
@@ -3,15 +3,15 @@ module DucksboardReporter
3
3
  include Celluloid
4
4
  include Celluloid::Logger
5
5
 
6
- attr_reader :options
7
- attr_accessor :value
6
+ attr_accessor :value, :timestamp, :name, :options
8
7
 
9
- def initialize(options = {})
8
+ def initialize(name, options = {})
9
+ @name = name
10
10
  @options = options
11
11
  end
12
12
 
13
13
  def start
14
- debug log_format("Started")
14
+ debug(log_format("Started"))
15
15
  async.collect
16
16
  end
17
17
 
@@ -21,14 +21,10 @@ module DucksboardReporter
21
21
  @timestamp || Time.now.to_i
22
22
  end
23
23
 
24
- def to_s
25
- options.name
26
- end
27
-
28
24
  private
29
25
 
30
26
  def log_format(msg)
31
- @log_prefix ||= "Reporter #{self.class.name.split("::").last}(#{to_s}): "
27
+ @log_prefix ||= "Reporter #{self.class.name.split("::").last}(#{@name}): "
32
28
  @log_prefix + msg
33
29
  end
34
30
  end
@@ -9,9 +9,9 @@ module DucksboardReporter
9
9
  nosrvs = 0
10
10
 
11
11
  begin
12
- file = File.open(options.logfile, "r")
12
+ file = File.open(options[:log_file], "r")
13
13
  rescue Errno::ENOENT
14
- error("HaproxyLogRequests: Cannot open #{options.logfile}")
14
+ error("HaproxyLogRequests: Cannot open #{options[:log_file]}")
15
15
  return
16
16
  end
17
17
 
@@ -1,3 +1,3 @@
1
1
  module DucksboardReporter
2
- VERSION = "0.0.7"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -3,35 +3,31 @@ module DucksboardReporter
3
3
  include Celluloid
4
4
  include Celluloid::Logger
5
5
 
6
- attr_reader :id, :reporter, :options
6
+ attr_reader :id, :reporter, :options, :updater
7
7
 
8
8
  def initialize(klass, id, reporter, options = {})
9
9
  @klass = klass
10
10
  @id = id
11
11
  @reporter = reporter
12
12
  @options = options
13
- @widget = instanciate_widget
13
+ @updater = instanciate_updater
14
14
  end
15
15
 
16
16
  def start
17
- debug log_format("Started with reporter #{reporter}")
17
+ debug log_format("Started using reporter #{reporter.name}")
18
18
 
19
19
  every(interval) do
20
- begin
21
- update
22
- rescue Net::OpenTimeout
23
- # ignore unseccessful updates
24
- end
20
+ update
25
21
  end
26
22
  end
27
23
 
28
24
  def update
29
25
  value = case value_method
30
26
  when Symbol
31
- reporter.public_send(value_method)
27
+ @reporter.public_send(value_method)
32
28
  when Hash
33
29
  value_method.inject({}) do |memo, (k, v)|
34
- memo[k] = (v.is_a?(Symbol) ? reporter.public_send(v) : v)
30
+ memo[k] = (v.is_a?(Symbol) ? @reporter.public_send(v) : v)
35
31
  memo
36
32
  end
37
33
  else
@@ -40,30 +36,30 @@ module DucksboardReporter
40
36
 
41
37
  debug log_format("Updating value #{value}")
42
38
 
43
- @widget.update(value)
44
- rescue Net::ReadTimeout
39
+ @updater.update(value)
40
+ rescue Net::ReadTimeout, Net::OpenTimeout
45
41
  # accept timeout errors
46
42
  end
47
43
 
48
44
  def interval
49
- options.interval || 10
45
+ options[:interval] || 10
50
46
  end
51
47
 
52
48
  private
53
49
 
54
50
  def log_format(msg)
55
- @log_prefix ||= "Widget #{self.class.name.split("::").last}(#{id}): "
51
+ @log_prefix ||= "Widget #{@klass}(#{id}): "
56
52
  @log_prefix + msg
57
53
  end
58
54
 
59
55
  def value_method
60
- options.value || :value
56
+ options[:value] || :value
61
57
  end
62
58
 
63
- def instanciate_widget
59
+ def instanciate_updater
64
60
  klass = Class.new(Ducksboard::Widget)
65
61
  klass.default_timeout(interval - 1)
66
- klass.new(id)
62
+ klass.new(@id)
67
63
  end
68
64
  end
69
65
  end
@@ -1,77 +1,89 @@
1
1
  require "rubygems"
2
2
 
3
3
  require "logger"
4
- require "hashie"
5
4
  require "celluloid"
6
5
  require "timers"
7
6
  require "ducksboard"
7
+ require "hashie/extensions/symbolize_keys"
8
+ Hash.include Hashie::Extensions::SymbolizeKeys
8
9
 
9
10
  require "ducksboard_reporter/version"
10
11
  require "ducksboard_reporter/reporter"
11
- require "ducksboard_reporter/reporters"
12
12
  require "ducksboard_reporter/widget"
13
13
 
14
+ require "ducksboard_reporter/reporters/random"
15
+ require "ducksboard_reporter/reporters/haproxy_log_requests"
16
+ require "ducksboard_reporter/reporters/cpu_usage"
17
+
14
18
  Thread.abort_on_exception = true
15
19
 
16
20
  module DucksboardReporter
17
21
  extend self
18
- include Celluloid::Logger
19
-
20
- def config
21
- @config ||= Hashie::Mash.load(config_file)
22
- end
23
22
 
24
- def config_file
25
- @config_file
26
- end
27
-
28
- def config_file=(file)
29
- @config_file = file
30
- end
23
+ include Celluloid::Logger
31
24
 
32
25
  def logger
33
26
  @logger ||= Celluloid.logger = Logger.new($stdout)
34
27
  end
35
28
 
36
- def reporters
37
- @reporters ||= {}
38
- end
29
+ class App
39
30
 
40
- def widgets
41
- @widgets ||= []
42
- end
31
+ attr_reader :config, :reporters, :widgets
43
32
 
44
- def start
45
- Signal.trap("INT") { exit }
33
+ def initialize(config)
34
+ @config = config.symbolize_keys!
35
+ register_reporters
36
+ register_widgets
37
+ end
46
38
 
47
- Ducksboard.api_key = config.api_key
39
+ def start
40
+ Signal.trap("INT") { exit }
48
41
 
49
- instanciate_reporters
50
- instanciate_widgets
42
+ Ducksboard.api_key = config[:api_key]
51
43
 
52
- sleep
53
- end
44
+ start_reporters
45
+ start_widgets
54
46
 
55
- def instanciate_reporters
56
- DucksboardReporter.config.reporters.each do |config|
57
- reporter = Reporters.const_get(config.type, false).new(config)
58
- reporters[config.name] = reporter
59
- reporter.start
47
+ sleep # let the actors continue their work
60
48
  end
61
- end
62
49
 
63
- def instanciate_widgets
64
- DucksboardReporter.config.widgets.each do |config|
65
- reporter = reporters[config.reporter]
50
+ def register_reporters
51
+ @reporters = {}
66
52
 
67
- unless reporter
68
- logger.error("Cannot find reporter #{config.reporter}")
69
- exit
53
+ @config[:reporters].each do |config|
54
+ reporter = Reporters.const_get(config[:type], false).new(config[:name], config[:options])
55
+ @reporters[reporter.name] = reporter
70
56
  end
57
+ end
58
+
59
+ def register_widgets
60
+ @widgets = []
61
+
62
+ @config[:widgets].each do |config|
63
+ reporter = @reporters.fetch(config[:reporter])
64
+
65
+ unless reporter
66
+ logger.error("Cannot find reporter #{config[:reporter]}")
67
+ exit
68
+ end
69
+
70
+ widget = Widget.new(config[:type], config[:id], reporter, config)
71
+ @widgets << widget
72
+ end
73
+ end
74
+
75
+ def start_reporters
76
+ @reporters.each {|_, reporter| reporter.start }
77
+ end
78
+
79
+ def start_widgets
80
+ @widgets.each(&:start)
81
+ end
82
+
83
+ private
71
84
 
72
- widget = Widget.new(config.type, config.id, reporter, config)
73
- widget.start
74
- widgets << widget
85
+ def logger
86
+ DucksboardReporter.logger
75
87
  end
76
88
  end
77
89
  end
@@ -0,0 +1,43 @@
1
+ require "spec_helper"
2
+
3
+ class DucksboardReporter::Reporters::FooBar < DucksboardReporter::Reporter
4
+ attr_accessor :log_file
5
+ end
6
+
7
+ describe DucksboardReporter::App do
8
+ let(:config) { YAML.load_file(File.expand_path("../config.yml", __FILE__)) }
9
+ let(:app) { DucksboardReporter::App.new(config) }
10
+ let(:reporter) { app.reporters["foo_bar"] }
11
+ let(:widget) { app.widgets.first }
12
+
13
+ it "registers reporters from config" do
14
+ expect(app.reporters.values.map(&:class)).to include(DucksboardReporter::Reporters::Random)
15
+ end
16
+
17
+ it "registers widgets from config" do
18
+ expect(app.widgets.map(&:class)).to include(DucksboardReporter::Widget)
19
+ end
20
+
21
+ describe "single reporter" do
22
+
23
+ it "sets name from config" do
24
+ expect(reporter.name).to eq("foo_bar")
25
+ end
26
+
27
+ it "applies options to reporters" do
28
+ expect(reporter.options[:log_file]).to eq("/var/log/haproxy.log")
29
+ end
30
+ end
31
+
32
+ describe "single widget" do
33
+
34
+ it "sets id from config" do
35
+ expect(widget.id).to eq(1234)
36
+ end
37
+
38
+ it "references reporter" do
39
+ expect(widget.reporter).to eq(reporter)
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+
3
+
4
+ class FooReporter < DucksboardReporter::Reporter
5
+ attr_accessor :log_file, :condition
6
+
7
+ def initialize(*args)
8
+ @condition = Celluloid::Condition.new
9
+ super
10
+ end
11
+
12
+ def collect
13
+ sleep 0.001
14
+ @condition.signal("called")
15
+ end
16
+
17
+ def collect_called
18
+ @condition.wait
19
+ true
20
+ end
21
+ end
22
+
23
+ describe DucksboardReporter::Reporter do
24
+
25
+ let(:reporter) { FooReporter.new("foo") }
26
+
27
+ describe "#collect" do
28
+ it "will be called on start" do
29
+ reporter.start
30
+ expect(reporter.collect_called).to be(true)
31
+ end
32
+ end
33
+
34
+ describe "#timestamp" do
35
+ it "returns current time" do
36
+ expect(reporter.timestamp).to be_within(1).of(Time.now.to_i)
37
+ end
38
+
39
+ it "returns set timestamp" do
40
+ time = Time.now.to_i + 10
41
+ reporter.timestamp = time
42
+ expect(reporter.timestamp).to eq(time)
43
+ end
44
+ end
45
+ end
46
+
@@ -0,0 +1,7 @@
1
+ require "ducksboard_reporter"
2
+ require "byebug"
3
+
4
+ DucksboardReporter.logger.level = Logger::FATAL
5
+
6
+ RSpec.configure do |config|
7
+ end
@@ -0,0 +1,73 @@
1
+ require "spec_helper"
2
+
3
+ class WidgetReporter < DucksboardReporter::Reporter
4
+ def value
5
+ 23
6
+ end
7
+
8
+ def other_value
9
+ 99
10
+ end
11
+ end
12
+
13
+ describe DucksboardReporter::Widget do
14
+
15
+ let(:reporter) { WidgetReporter.new("name") }
16
+ let(:widget) { DucksboardReporter::Widget.new("Box", 1234, reporter) }
17
+
18
+ describe "#update" do
19
+ it "updates value from reporter" do
20
+ expect(widget.updater).to receive(:update).with(23)
21
+ widget.update
22
+ end
23
+
24
+ it "will not crash on Net::ReadTimeout" do
25
+ expect(widget.updater).to receive(:update).and_raise(Net::ReadTimeout)
26
+ widget.update
27
+ end
28
+
29
+ it "will not crash on Net::OpenTimeout" do
30
+ expect(widget.updater).to receive(:update).and_raise(Net::OpenTimeout)
31
+ widget.update
32
+ end
33
+
34
+ it "uses static values for update" do
35
+ widget = DucksboardReporter::Widget.new("Box", 1234, reporter, value: "hello")
36
+ expect(widget.updater).to receive(:update).with("hello")
37
+ widget.update
38
+ end
39
+
40
+ it "uses Symbols for method reference" do
41
+ widget = DucksboardReporter::Widget.new("Box", 1234, reporter, value: :other_value)
42
+ expect(widget.updater).to receive(:update).with(99)
43
+ widget.update
44
+ end
45
+
46
+ it "uses a Hash for contructing complex values " do
47
+ widget = DucksboardReporter::Widget.new("Box", 1234, reporter, value: {current: :value, foo: "bar"})
48
+ expect(widget.updater).to receive(:update).with(current: 23, foo: "bar")
49
+ widget.update
50
+ end
51
+ end
52
+
53
+ describe "#interval" do
54
+ it "retuns default value" do
55
+ expect(widget.interval).to eq(10)
56
+ end
57
+
58
+ it "returns interval option" do
59
+ widget = DucksboardReporter::Widget.new("Box", 1234, reporter, interval: 20)
60
+ expect(widget.interval).to eq(20)
61
+ end
62
+ end
63
+
64
+ describe "#start" do
65
+ it "calls update every interval" do
66
+ widget = DucksboardReporter::Widget.new("Box", 1234, reporter, interval: 0.001)
67
+ expect(widget.updater).to receive(:update).at_least(:once)
68
+ widget.start
69
+ sleep 0.002
70
+ end
71
+ end
72
+ end
73
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ducksboard_reporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - unnu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-28 00:00:00.000000000 Z
11
+ date: 2014-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -39,13 +39,13 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: ducksboard
42
+ name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
- type: :runtime
48
+ type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
@@ -53,13 +53,13 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: hashie
56
+ name: fuubar
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
- type: :runtime
62
+ type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
@@ -67,47 +67,89 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: celluloid
70
+ name: byebug
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
- type: :runtime
76
+ type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: ducksboard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.1.6
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.1.6
97
+ - !ruby/object:Gem::Dependency
98
+ name: hashie
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 3.3.1
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 3.3.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: celluloid
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.16'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.16'
83
125
  - !ruby/object:Gem::Dependency
84
126
  name: timers
85
127
  requirement: !ruby/object:Gem::Requirement
86
128
  requirements:
87
129
  - - ">="
88
130
  - !ruby/object:Gem::Version
89
- version: '0'
131
+ version: 1.1.0
90
132
  type: :runtime
91
133
  prerelease: false
92
134
  version_requirements: !ruby/object:Gem::Requirement
93
135
  requirements:
94
136
  - - ">="
95
137
  - !ruby/object:Gem::Version
96
- version: '0'
138
+ version: 1.1.0
97
139
  - !ruby/object:Gem::Dependency
98
140
  name: trollop
99
141
  requirement: !ruby/object:Gem::Requirement
100
142
  requirements:
101
143
  - - ">="
102
144
  - !ruby/object:Gem::Version
103
- version: '0'
145
+ version: 1.16.2
104
146
  type: :runtime
105
147
  prerelease: false
106
148
  version_requirements: !ruby/object:Gem::Requirement
107
149
  requirements:
108
150
  - - ">="
109
151
  - !ruby/object:Gem::Version
110
- version: '0'
152
+ version: 1.16.2
111
153
  description: Report values to ducksboard
112
154
  email:
113
155
  - norman.timmler@gmail.com
@@ -126,13 +168,16 @@ files:
126
168
  - example_config.yml
127
169
  - lib/ducksboard_reporter.rb
128
170
  - lib/ducksboard_reporter/reporter.rb
129
- - lib/ducksboard_reporter/reporters.rb
130
171
  - lib/ducksboard_reporter/reporters/bandwidth.rb
131
172
  - lib/ducksboard_reporter/reporters/cpu_usage.rb
132
173
  - lib/ducksboard_reporter/reporters/haproxy_log_requests.rb
133
174
  - lib/ducksboard_reporter/reporters/random.rb
134
175
  - lib/ducksboard_reporter/version.rb
135
176
  - lib/ducksboard_reporter/widget.rb
177
+ - spec/ducksboard_reporter_spec.rb
178
+ - spec/reporter_spec.rb
179
+ - spec/spec_helper.rb
180
+ - spec/widget_spec.rb
136
181
  homepage: ''
137
182
  licenses:
138
183
  - MIT
@@ -157,4 +202,8 @@ rubygems_version: 2.2.2
157
202
  signing_key:
158
203
  specification_version: 4
159
204
  summary: Report values to ducksboard
160
- test_files: []
205
+ test_files:
206
+ - spec/ducksboard_reporter_spec.rb
207
+ - spec/reporter_spec.rb
208
+ - spec/spec_helper.rb
209
+ - spec/widget_spec.rb
@@ -1,6 +0,0 @@
1
- module DucksboardReporter
2
- module Reporters
3
- end
4
- end
5
-
6
- Dir[File.dirname(__FILE__) + '/reporters/*.rb'].each {|file| require file }