impression 0.1 → 0.5

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/test.yml +32 -0
  4. data/CHANGELOG.md +23 -0
  5. data/Gemfile +5 -0
  6. data/Gemfile.lock +63 -32
  7. data/README.md +44 -2
  8. data/Rakefile +10 -0
  9. data/examples/markdown/_assets/style.css +98 -0
  10. data/examples/markdown/app.rb +11 -5
  11. data/examples/markdown/docs/tutorial.md +15 -0
  12. data/impression.gemspec +11 -7
  13. data/lib/impression/app.rb +9 -0
  14. data/lib/impression/file_tree.rb +124 -0
  15. data/lib/impression/file_watcher.rb +50 -0
  16. data/lib/impression/jamstack.rb +179 -0
  17. data/lib/impression/request_extensions/responses.rb +48 -0
  18. data/lib/impression/request_extensions/routing.rb +52 -0
  19. data/lib/impression/request_extensions.rb +8 -2
  20. data/lib/impression/resource.rb +168 -0
  21. data/lib/impression/version.rb +1 -1
  22. data/lib/impression.rb +8 -0
  23. data/test/helper.rb +94 -0
  24. data/test/jamstack/_layouts/article.rb +9 -0
  25. data/test/jamstack/_layouts/default.rb +12 -0
  26. data/test/jamstack/articles/2008-06-14-manu.md +6 -0
  27. data/test/jamstack/articles/2009-06-12-noatche.md +6 -0
  28. data/test/jamstack/articles/a.md +6 -0
  29. data/test/jamstack/assets/js/a.js +1 -0
  30. data/test/jamstack/bar.html +1 -0
  31. data/test/jamstack/baz/index.md +7 -0
  32. data/test/jamstack/foo.rb +7 -0
  33. data/test/jamstack/foobar.rb +10 -0
  34. data/test/jamstack/index.md +4 -0
  35. data/test/run.rb +5 -0
  36. data/test/static/bar/index.html +1 -0
  37. data/test/static/foo.html +1 -0
  38. data/test/static/index.html +1 -0
  39. data/test/static/js/a.js +1 -0
  40. data/test/test_app.rb +52 -0
  41. data/test/test_file_tree.rb +116 -0
  42. data/test/test_file_watcher.rb +57 -0
  43. data/test/test_jamstack.rb +263 -0
  44. data/test/test_resource.rb +201 -0
  45. metadata +57 -35
  46. data/lib/impression/pages.rb +0 -120
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f5a7e55ef9ff6c795a485a4b1e50456949932d923425ad447ada836ef2e69b0c
4
- data.tar.gz: 669f0781d30986542fb09aad0af058107a658281136ace716edfdefc18fefabb
3
+ metadata.gz: 8db17f3627f0b8de2ed13a81effd9689f8a292b0861104c276d343bf5ec23e8f
4
+ data.tar.gz: 79cc272aed0503e1514723815f7019002c780a890995ef7c6f2d4718d9704000
5
5
  SHA512:
6
- metadata.gz: 1cdbfd6167b1e1717e5a3fda6089c84bb0ed7c6d810b1dac9376a1cd81a38a473c097ba6dd6ecbd07c61145b86b5e10f13c8be02ac69c14c556ba6991f87e4f4
7
- data.tar.gz: cf2e071b60b5ed0aa0ab826d2721c55d15cabb7fa0f63e84d068f76eef9a39db68159d6a651ddf5371976c4703a72a910883e50becdd64ff365d4b955cb93192
6
+ metadata.gz: 46112700200e6018c10b9a84b3a90184ce590e0da7369096a787467af4c84aba6578c043c1c9ad520cfa6da83638492def2c53b8cc9d51407d74695e3c12af4f
7
+ data.tar.gz: 94b1e171d6161bdd452ce27a6ee5effde4c9a1fdb2fd0247b72449fcb7048a8c1800dc616c6e291d56ea639dcec8a4d2d2dad5e9aa6865ccc0cb96cac4525688
@@ -0,0 +1 @@
1
+ github: ciconia
@@ -0,0 +1,32 @@
1
+ name: Tests
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ os: [ubuntu-latest, macos-latest]
11
+ ruby: ['2.7', '3.0', '3.1', 'head']
12
+
13
+ name: >-
14
+ ${{matrix.os}}, ${{matrix.ruby}}
15
+
16
+ runs-on: ${{matrix.os}}
17
+
18
+ env:
19
+ POLYPHONY_USE_LIBEV: "1"
20
+
21
+ steps:
22
+ - name: Setup machine
23
+ uses: actions/checkout@v1
24
+ - name: Setup Ruby and install deps
25
+ uses: ruby/setup-ruby@v1
26
+ with:
27
+ ruby-version: ${{matrix.ruby}}
28
+ bundler-cache: true # 'bundle install' and cache
29
+ cache-version: 1
30
+
31
+ - name: Run tests
32
+ run: bundle exec rake test
data/CHANGELOG.md CHANGED
@@ -0,0 +1,23 @@
1
+ # 0.5 2022-01-20
2
+
3
+ - Pass resource and request to rendered templates (#8)
4
+ - Implement Jamstack#page_list method (#7)
5
+
6
+ # 0.4 2022-01-19
7
+
8
+ - Remove deprecated Pages code (#6)
9
+
10
+ # 0.3 2022-01-19
11
+
12
+ - Implement basic Jamstack resource (#5)
13
+ - Add support for stock callable responses (#4)
14
+ - Make resource callable, rename `#respond` to `#callable` (#3)
15
+
16
+ ## 0.2 2022-01-13
17
+
18
+ - Implement `FileTree` (#2)
19
+ - Rename `Resource#render` to `Resource#respond`
20
+ - Rewrite resource routing (#1)
21
+ - Implement `Resource`
22
+
23
+ ## 0.1 2021-02-24
data/Gemfile CHANGED
@@ -1,3 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ # %w{polyphony tipi qeweney papercraft}.each do |dep|
6
+ # dir = "../#{dep}"
7
+ # gem(dep, path: dir) if File.directory?(dir)
8
+ # end
data/Gemfile.lock CHANGED
@@ -1,66 +1,97 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- impression (0.1)
5
- kramdown (~> 2.3.0)
6
- kramdown-parser-gfm (~> 1.1.0)
7
- polyphony (~> 0.51.0)
8
- rouge (~> 3.26.0)
9
- tipi (~> 0.37)
4
+ impression (0.5)
5
+ modulation (~> 1.1)
6
+ papercraft (~> 0.14)
7
+ polyphony (~> 0.73.1)
8
+ qeweney (~> 0.15)
9
+ tipi (~> 0.45)
10
10
 
11
11
  GEM
12
12
  remote: https://rubygems.org/
13
13
  specs:
14
- ansi (1.5.0)
15
- builder (3.2.4)
16
- docile (1.3.5)
14
+ acme-client (2.0.9)
15
+ faraday (>= 0.17, < 2.0.0)
16
+ docile (1.4.0)
17
17
  escape_utils (1.2.1)
18
- http-2 (0.10.2)
19
- http_parser.rb (0.6.0)
20
- json (2.5.1)
21
- kramdown (2.3.0)
18
+ ever (0.1)
19
+ extralite (1.11)
20
+ faraday (1.9.3)
21
+ faraday-em_http (~> 1.0)
22
+ faraday-em_synchrony (~> 1.0)
23
+ faraday-excon (~> 1.1)
24
+ faraday-httpclient (~> 1.0)
25
+ faraday-multipart (~> 1.0)
26
+ faraday-net_http (~> 1.0)
27
+ faraday-net_http_persistent (~> 1.0)
28
+ faraday-patron (~> 1.0)
29
+ faraday-rack (~> 1.0)
30
+ faraday-retry (~> 1.0)
31
+ ruby2_keywords (>= 0.0.4)
32
+ faraday-em_http (1.0.0)
33
+ faraday-em_synchrony (1.0.0)
34
+ faraday-excon (1.1.0)
35
+ faraday-httpclient (1.0.1)
36
+ faraday-multipart (1.0.3)
37
+ multipart-post (>= 1.2, < 3)
38
+ faraday-net_http (1.0.1)
39
+ faraday-net_http_persistent (1.2.0)
40
+ faraday-patron (1.0.0)
41
+ faraday-rack (1.0.0)
42
+ faraday-retry (1.0.3)
43
+ h1p (0.2)
44
+ http-2 (0.11.0)
45
+ json (2.6.1)
46
+ kramdown (2.3.1)
22
47
  rexml
23
48
  kramdown-parser-gfm (1.1.0)
24
49
  kramdown (~> 2.0)
50
+ localhost (1.1.9)
25
51
  minitest (5.11.3)
26
- minitest-reporters (1.4.3)
27
- ansi
28
- builder
29
- minitest (>= 5.0)
30
- ruby-progressbar
31
- msgpack (1.4.2)
32
- polyphony (0.51.0)
33
- qeweney (0.5)
52
+ modulation (1.1)
53
+ msgpack (1.4.3)
54
+ multipart-post (2.1.1)
55
+ papercraft (0.14)
56
+ escape_utils (= 1.2.1)
57
+ kramdown (~> 2.3.0)
58
+ kramdown-parser-gfm (~> 1.1.0)
59
+ rouge (~> 3.26.0)
60
+ polyphony (0.73.1)
61
+ qeweney (0.15)
34
62
  escape_utils (~> 1.2.1)
35
63
  rack (2.2.3)
36
64
  rake (12.3.3)
37
- rexml (3.2.4)
38
- rouge (3.26.0)
39
- ruby-progressbar (1.11.0)
65
+ rexml (3.2.5)
66
+ rouge (3.26.1)
67
+ ruby2_keywords (0.0.5)
40
68
  simplecov (0.17.1)
41
69
  docile (~> 1.1)
42
70
  json (>= 1.8, < 3)
43
71
  simplecov-html (~> 0.10.0)
44
72
  simplecov-html (0.10.2)
45
- tipi (0.37)
46
- http-2 (~> 0.10.0)
47
- http_parser.rb (~> 0.6.0)
73
+ tipi (0.45)
74
+ acme-client (~> 2.0.8)
75
+ ever (~> 0.1)
76
+ extralite (~> 1.2)
77
+ h1p (~> 0.2)
78
+ http-2 (~> 0.11)
79
+ localhost (~> 1.1.4)
48
80
  msgpack (~> 1.4.2)
49
- polyphony (~> 0.51.0)
50
- qeweney (~> 0.5)
81
+ polyphony (~> 0.71)
82
+ qeweney (~> 0.14)
51
83
  rack (>= 2.0.8, < 2.3.0)
52
84
  websocket (~> 1.2.8)
53
85
  websocket (1.2.9)
54
86
 
55
87
  PLATFORMS
56
- ruby
88
+ x86_64-linux
57
89
 
58
90
  DEPENDENCIES
59
91
  impression!
60
92
  minitest (~> 5.11.3)
61
- minitest-reporters (~> 1.4.2)
62
93
  rake (~> 12.3.3)
63
94
  simplecov (~> 0.17.1)
64
95
 
65
96
  BUNDLED WITH
66
- 2.1.4
97
+ 2.3.3
data/README.md CHANGED
@@ -1,2 +1,44 @@
1
- # impression
2
- A modern web framework for Ruby
1
+ <h1 align="center">
2
+ Impression
3
+ </h1>
4
+
5
+ <h4 align="center">A modern web framework for Ruby</h4>
6
+
7
+ <p align="center">
8
+ <a href="http://rubygems.org/gems/impression">
9
+ <img src="https://badge.fury.io/rb/impression.svg" alt="Ruby gem">
10
+ </a>
11
+ <a href="https://github.com/digital-fabric/impression/actions?query=workflow%3ATests">
12
+ <img src="https://github.com/digital-fabric/impression/workflows/Tests/badge.svg" alt="Tests">
13
+ </a>
14
+ <a href="https://github.com/digital-fabric/impression/blob/master/LICENSE">
15
+ <img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License">
16
+ </a>
17
+ </p>
18
+
19
+ ## What is Impression
20
+
21
+ > Impression is still in a very early stage of development. Things might not
22
+ > correctly, or not at all.
23
+
24
+ Impression is a modern web framework for Ruby. Unlike other web framework,
25
+ Impression does not impose any rigid structure or paradigm, but instead provides
26
+ a set of tools letting you build any kind of web app, by freely mixing different
27
+ kinds of web resources, be they static files, structured templates, Jamstack
28
+ sites, or dynamic APIs.
29
+
30
+ In Impression, resources can be composed into a hierarchical tree, allowing
31
+ combining of multiple web apps, or web subsystems, into a single URL hierarchy.
32
+
33
+ Impression is made for running on top of
34
+ [Tipi](https://github.com/digital-fabric/tipi), a new all-in-one web server for
35
+ Ruby.
36
+
37
+ ## I want to know more
38
+
39
+ Further documentation is coming real soon (TM)...
40
+
41
+ ## Contributing
42
+
43
+ Contributions in the form of issues, PRs or comments will be greatly
44
+ appreciated!
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/clean"
5
+
6
+ task :default => [:test]
7
+
8
+ task :test do
9
+ exec 'ruby test/run.rb'
10
+ end
@@ -0,0 +1,98 @@
1
+ * {
2
+ border: 0;
3
+ font: inherit;
4
+ font-size: 100%;
5
+ vertical-align: baseline;
6
+ margin: 0;
7
+ padding: 0;
8
+ color: black;
9
+ }
10
+
11
+ body {
12
+ font: normal 14px monospace;
13
+ }
14
+
15
+ h1, h2 {
16
+ font-weight: bold;
17
+ }
18
+
19
+ header {
20
+ margin-bottom: 20px;
21
+ }
22
+
23
+ a {
24
+ color: -webkit-link;
25
+ }
26
+
27
+ li {
28
+ margin-left: 40px;
29
+ }
30
+
31
+ em {
32
+ font-style: italic;
33
+ }
34
+
35
+ strong {
36
+ font-weight: bold;
37
+ }
38
+
39
+ p, ul, ol {
40
+ margin: 20px;
41
+ }
42
+
43
+ pre {
44
+ margin-bottom: 20px;
45
+ padding: 20px 5px;
46
+ overflow-x: visible;
47
+ }
48
+
49
+ pre code {
50
+ word-wrap: no;
51
+ }
52
+
53
+ hr {
54
+ display: block;
55
+ margin-top: 0.5em;
56
+ margin-bottom: 0.5em;
57
+ margin-left: auto;
58
+ margin-right: auto;
59
+ border-style: inset;
60
+ border-width: 1px;
61
+ }
62
+
63
+ #nav {
64
+ padding: 20px 5px;
65
+ }
66
+
67
+ #nav, #content, footer {
68
+ margin: 0 20px;
69
+ max-width: 580px;
70
+ }
71
+
72
+ #nav h1 {
73
+ margin-bottom: 20px;
74
+ }
75
+
76
+ iframe {
77
+ margin: 20px;
78
+ max-width: 530px;
79
+ }
80
+
81
+ #content img {
82
+ max-width: 100%;
83
+ }
84
+
85
+ #title {
86
+ margin-top: 40px;
87
+ font-weight: bold;
88
+ text-align: center;
89
+ }
90
+
91
+ #date {
92
+ display: block;
93
+ text-align: right;
94
+ }
95
+
96
+ #webring {
97
+ padding-bottom: 10px;
98
+ }
@@ -11,13 +11,19 @@ opts = {
11
11
  }
12
12
 
13
13
  puts "pid: #{Process.pid}"
14
- puts 'Listening on port 4411...'
15
14
 
16
- Tipi.serve('0.0.0.0', 4411, opts) do |req|
17
- app.call(req)
15
+ Tipi.full_service do |req|
16
+ req.route do
17
+ if req.host != 'noteflakes.com'
18
+ req.respond(nil, ':status' => Qeweney::Status::SERVICE_UNAVAILABLE)
19
+ stop_routing
20
+ end
21
+ req.on('assets') { req.serve_file(req.route_relative_path, base_path: File.join(__dir__, '_assets')) }
22
+ req.default { app.call(req) }
23
+ end
18
24
  rescue Exception => e
19
- p e
20
- puts e.backtrace.join("\n")
25
+ p [req.path, e]
26
+ # puts e.backtrace.join("\n")
21
27
  status = e.respond_to?(:http_status) ? e.http_status : 500
22
28
  req.respond(e.inspect, ':status' => status)
23
29
  end
@@ -0,0 +1,15 @@
1
+ # This is a tutorial
2
+
3
+ ## I'm an h2
4
+
5
+ ```ruby
6
+ "here's some code"
7
+
8
+ class A
9
+ def b
10
+ [:c, 42, /foo/]
11
+ end
12
+ end
13
+
14
+ p A.new.b
15
+ ```
data/impression.gemspec CHANGED
@@ -10,7 +10,10 @@ Gem::Specification.new do |s|
10
10
  s.files = `git ls-files`.split
11
11
  s.homepage = 'http://github.com/digital-fabric/impression'
12
12
  s.metadata = {
13
- "source_code_uri" => "https://github.com/digital-fabric/impression"
13
+ "source_code_uri" => "https://github.com/digital-fabric/impression",
14
+ "documentation_uri" => "https://www.rubydoc.info/gems/impression",
15
+ "homepage_uri" => "https://github.com/digital-fabric/impression",
16
+ "changelog_uri" => "https://github.com/digital-fabric/impression/blob/master/CHANGELOG.md"
14
17
  }
15
18
  s.rdoc_options = ["--title", "impression", "--main", "README.md"]
16
19
  s.extra_rdoc_files = ["README.md"]
@@ -19,15 +22,16 @@ Gem::Specification.new do |s|
19
22
 
20
23
  # s.executables = ['impression']
21
24
 
22
- s.add_runtime_dependency 'polyphony', '~>0.51.0'
23
- s.add_runtime_dependency 'tipi', '~>0.37'
24
- s.add_runtime_dependency 'kramdown', '~>2.3.0'
25
- s.add_runtime_dependency 'rouge', '~>3.26.0'
26
- s.add_runtime_dependency 'kramdown-parser-gfm', '~>1.1.0'
25
+ s.add_runtime_dependency 'polyphony', '~>0.73.1'
26
+ s.add_runtime_dependency 'tipi', '~>0.45'
27
+ s.add_runtime_dependency 'qeweney', '~>0.15'
28
+
29
+ # s.add_runtime_dependency 'rb-inotify', '~>0.10.1'
30
+ s.add_runtime_dependency 'papercraft', '~>0.14'
31
+ s.add_runtime_dependency 'modulation', '~>1.1'
27
32
 
28
33
 
29
34
  s.add_development_dependency 'rake', '~>12.3.3'
30
35
  s.add_development_dependency 'minitest', '~>5.11.3'
31
- s.add_development_dependency 'minitest-reporters', '~>1.4.2'
32
36
  s.add_development_dependency 'simplecov', '~>0.17.1'
33
37
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Impression
4
+ class App < Resource
5
+ def initialize(path: '/', **opts)
6
+ super(path: path, **opts)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require_relative './resource'
5
+
6
+ module Impression
7
+
8
+ # `FileTree` implements a resource that maps to a static file hierarchy.
9
+ class FileTree < Resource
10
+
11
+ # Initializes a `FileTree` resource.
12
+ #
13
+ # @param directory [String] static directory path
14
+ # @return [void]
15
+ def initialize(directory:, **props)
16
+ super(**props)
17
+ @directory = directory
18
+ @path_info_cache = {}
19
+ end
20
+
21
+ # Responds to a request.
22
+ #
23
+ # @param req [Qeweney::Request] request
24
+ # @return [void]
25
+ def call(req)
26
+ path_info = get_path_info(req.resource_relative_path)
27
+ render_from_path_info(req, path_info)
28
+ end
29
+
30
+ private
31
+
32
+ # Renders a response from the given response kind and path.
33
+ #
34
+ # @param req [Qeweney::Request] request
35
+ # @param kind [Symbol] path kind (`:not_found` or `:file`)
36
+ # @param path [String, nil] file path
37
+ def render_from_path_info(req, path_info)
38
+ case path_info[:kind]
39
+ when :not_found
40
+ req.respond(nil, ':status' => Qeweney::Status::NOT_FOUND)
41
+ when :file
42
+ render_file(req, path_info)
43
+ else
44
+ raise "Invalid path info kind #{kind.inspect}"
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ # Renders a file response for the given request and the given path info.
51
+ #
52
+ # @param req [Qeweney::Request] request
53
+ # @param path_info [Hash] path info
54
+ # @return [void]
55
+ def render_file(req, path_info)
56
+ req.serve_file(path_info[:path])
57
+ end
58
+
59
+ # Returns the path info for the given relative path.
60
+ #
61
+ # @param path [String] relative path
62
+ # @return [Hash] path info
63
+ def get_path_info(path)
64
+ @path_info_cache[path] ||= calculate_path_info(path)
65
+ end
66
+
67
+ # Calculates the path info for the given relative path.
68
+ #
69
+ # @param path [String] relative path
70
+ # @param add_ext [bool] whether to add .html extension if not found
71
+ # @return [Hash] path info
72
+ def calculate_path_info(path)
73
+ full_path = File.join(@directory, path)
74
+
75
+ path_info(full_path) || search_path_info_with_extension(full_path) || { kind: :not_found }
76
+ end
77
+
78
+ # Returns the path info for the given path. If the path refers to a file,
79
+ # returns a hash containing the file information. If the path refers to a
80
+ # directory, performs a search for an index file using #directory_path_info.
81
+ # Otherwise, returns nil.
82
+ #
83
+ # @param path [String] path
84
+ # @return [Hash, nil] path info
85
+ def path_info(path)
86
+ stat = File.stat(path) rescue nil
87
+ if !stat
88
+ nil
89
+ elsif stat.directory?
90
+ return directory_path_info(path)
91
+ else
92
+ return { kind: :file, path: path, ext: File.extname(path) }
93
+ end
94
+ end
95
+
96
+ # Calculates the path info for a directory. If an index file exists, its
97
+ # path info is returned, otherwise, returns nil.
98
+ #
99
+ # @param path [String] directory path
100
+ # @return [Hash, nil] path info
101
+ def directory_path_info(path)
102
+ search_path_info_with_extension(File.join(path, 'index'))
103
+ end
104
+
105
+ # Returns the supported path extensions for paths without extension.
106
+ #
107
+ # @return [Array] supported extensions
108
+ def supported_path_extensions
109
+ [:html]
110
+ end
111
+
112
+ # Searches for files with extensions for the given path.
113
+ #
114
+ # @param path [String] path
115
+ # @return [Hash, nil] path info
116
+ def search_path_info_with_extension(path)
117
+ supported_path_extensions.each do |ext|
118
+ info = path_info("#{path}.#{ext}")
119
+ return info if info
120
+ end
121
+ nil
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rb-inotify'
4
+
5
+ module Impression
6
+ class FileWatcher
7
+ def initialize(spec)
8
+ @notifier = INotify::Notifier.new
9
+ @buffer = []
10
+ setup(spec)
11
+ end
12
+
13
+ def setup(spec)
14
+ if File.file?(spec)
15
+ setup_single_file(spec)
16
+ elsif File.directory?(spec)
17
+ setup_directory(spec)
18
+ else
19
+ dir = File.dir_name(spec)
20
+ filename = File.basename(spec)
21
+ if dir =~ /\/\*\*$/
22
+ dir = File.dir_name(dir)
23
+ filename = "**/#{filename}"
24
+ end
25
+ setup_directory(dir, filename)
26
+ end
27
+ end
28
+
29
+ def setup_directory(dir)
30
+ @notifier.watch(dir, :moved_to, :create, :move, :attrib, :modify, :delete) do |event|
31
+ kind = event.flags.first
32
+
33
+ @buffer << [kind, event.absolute_name]
34
+ end
35
+ end
36
+
37
+ def each(&block)
38
+ @receiver = Fiber.current
39
+ io = @notifier.to_io
40
+ loop do
41
+ io.wait_readable
42
+ @notifier.process
43
+ next if @buffer.empty?
44
+
45
+ @buffer.each(&block)
46
+ @buffer.clear
47
+ end
48
+ end
49
+ end
50
+ end