dry-effects 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +57 -5
  3. data/LICENSE +1 -1
  4. data/README.md +19 -11
  5. data/dry-effects.gemspec +33 -41
  6. data/lib/dry/effects/all.rb +4 -4
  7. data/lib/dry/effects/container.rb +1 -1
  8. data/lib/dry/effects/effect.rb +2 -2
  9. data/lib/dry/effects/effects/async.rb +3 -1
  10. data/lib/dry/effects/effects/cache.rb +13 -9
  11. data/lib/dry/effects/effects/cmp.rb +3 -1
  12. data/lib/dry/effects/effects/current_time.rb +4 -2
  13. data/lib/dry/effects/effects/defer.rb +3 -1
  14. data/lib/dry/effects/effects/env.rb +4 -2
  15. data/lib/dry/effects/effects/fork.rb +3 -1
  16. data/lib/dry/effects/effects/implicit.rb +4 -2
  17. data/lib/dry/effects/effects/interrupt.rb +4 -2
  18. data/lib/dry/effects/effects/lock.rb +8 -6
  19. data/lib/dry/effects/effects/parallel.rb +4 -2
  20. data/lib/dry/effects/effects/random.rb +5 -3
  21. data/lib/dry/effects/effects/reader.rb +1 -1
  22. data/lib/dry/effects/effects/resolve.rb +23 -3
  23. data/lib/dry/effects/effects/retry.rb +4 -2
  24. data/lib/dry/effects/effects/state.rb +4 -2
  25. data/lib/dry/effects/effects/timeout.rb +3 -1
  26. data/lib/dry/effects/effects/timestamp.rb +3 -1
  27. data/lib/dry/effects/errors.rb +4 -4
  28. data/lib/dry/effects/extensions/active_support/tagged_logging.rb +13 -0
  29. data/lib/dry/effects/extensions/auto_inject.rb +5 -5
  30. data/lib/dry/effects/extensions/system.rb +8 -7
  31. data/lib/dry/effects/extensions.rb +12 -4
  32. data/lib/dry/effects/frame.rb +30 -9
  33. data/lib/dry/effects/halt.rb +3 -3
  34. data/lib/dry/effects/handler.rb +1 -1
  35. data/lib/dry/effects/inflector.rb +1 -1
  36. data/lib/dry/effects/initializer.rb +17 -16
  37. data/lib/dry/effects/instruction.rb +1 -1
  38. data/lib/dry/effects/instructions/execute.rb +2 -1
  39. data/lib/dry/effects/instructions/raise.rb +2 -1
  40. data/lib/dry/effects/provider/class_interface.rb +2 -2
  41. data/lib/dry/effects/provider.rb +2 -2
  42. data/lib/dry/effects/providers/async.rb +2 -2
  43. data/lib/dry/effects/providers/cache.rb +2 -2
  44. data/lib/dry/effects/providers/cmp.rb +1 -1
  45. data/lib/dry/effects/providers/current_time/time_generators.rb +1 -1
  46. data/lib/dry/effects/providers/current_time.rb +5 -5
  47. data/lib/dry/effects/providers/defer.rb +6 -6
  48. data/lib/dry/effects/providers/env.rb +2 -2
  49. data/lib/dry/effects/providers/fork.rb +2 -2
  50. data/lib/dry/effects/providers/implicit.rb +1 -1
  51. data/lib/dry/effects/providers/interrupt.rb +3 -3
  52. data/lib/dry/effects/providers/lock.rb +6 -8
  53. data/lib/dry/effects/providers/parallel.rb +3 -3
  54. data/lib/dry/effects/providers/random.rb +74 -2
  55. data/lib/dry/effects/providers/reader.rb +1 -1
  56. data/lib/dry/effects/providers/resolve.rb +8 -7
  57. data/lib/dry/effects/providers/retry.rb +5 -7
  58. data/lib/dry/effects/providers/state.rb +2 -2
  59. data/lib/dry/effects/providers/timeout.rb +2 -2
  60. data/lib/dry/effects/providers/timestamp.rb +2 -2
  61. data/lib/dry/effects/stack.rb +6 -6
  62. data/lib/dry/effects/version.rb +1 -1
  63. data/lib/dry/effects.rb +7 -7
  64. metadata +22 -69
  65. data/.codeclimate.yml +0 -12
  66. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
  67. data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -30
  68. data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
  69. data/.github/workflows/ci.yml +0 -74
  70. data/.github/workflows/docsite.yml +0 -34
  71. data/.github/workflows/sync_configs.yml +0 -34
  72. data/.gitignore +0 -12
  73. data/.rspec +0 -4
  74. data/.rubocop.yml +0 -95
  75. data/CODE_OF_CONDUCT.md +0 -13
  76. data/CONTRIBUTING.md +0 -29
  77. data/Gemfile +0 -23
  78. data/Rakefile +0 -8
  79. data/docsite/source/effects/cache.html.md +0 -84
  80. data/docsite/source/effects/current_time.html.md +0 -186
  81. data/docsite/source/effects/defer.html.md +0 -130
  82. data/docsite/source/effects/env.html.md +0 -144
  83. data/docsite/source/effects/interrupt.html.md +0 -109
  84. data/docsite/source/effects/parallel.html.md +0 -25
  85. data/docsite/source/effects/reader.html.md +0 -126
  86. data/docsite/source/effects/resolve.html.md +0 -188
  87. data/docsite/source/effects/state.html.md +0 -178
  88. data/docsite/source/effects/timeout.html.md +0 -42
  89. data/docsite/source/effects.html.md +0 -29
  90. data/docsite/source/index.html.md +0 -212
  91. data/examples/cmp.rb +0 -51
  92. data/examples/state.rb +0 -29
@@ -1,34 +0,0 @@
1
- # this file is managed by dry-rb/devtools project
2
-
3
- name: docsite
4
-
5
- on:
6
- push:
7
- paths:
8
- - docsite/**
9
- - .github/workflows/docsite.yml
10
- branches:
11
- - master
12
- - release-**
13
- tags:
14
-
15
- jobs:
16
- update-docs:
17
- runs-on: ubuntu-latest
18
- steps:
19
- - uses: actions/checkout@v1
20
- - name: Set up Ruby
21
- uses: actions/setup-ruby@v1
22
- with:
23
- ruby-version: "2.6.x"
24
- - name: Install dependencies
25
- run: |
26
- gem install bundler
27
- bundle install --jobs 4 --retry 3 --without benchmarks sql
28
- - name: Symlink ossy
29
- run: mkdir -p bin && ln -sf "$(bundle show ossy)/bin/ossy" bin/ossy
30
- - name: Trigger dry-rb.org deploy
31
- env:
32
- GITHUB_LOGIN: dry-bot
33
- GITHUB_TOKEN: ${{ secrets.GH_PAT }}
34
- run: bin/ossy github workflow dry-rb/dry-rb.org ci
@@ -1,34 +0,0 @@
1
- # this file is managed by dry-rb/devtools project
2
-
3
- name: sync_configs
4
-
5
- on:
6
- repository_dispatch:
7
-
8
- jobs:
9
- sync-configs:
10
- runs-on: ubuntu-latest
11
- if: github.event.action == 'sync_configs'
12
- steps:
13
- - uses: actions/checkout@v1
14
- - name: Update configuration files from devtools
15
- env:
16
- GITHUB_LOGIN: dry-bot
17
- GITHUB_TOKEN: ${{ secrets.GH_PAT }}
18
- run: |
19
- git clone https://github.com/dry-rb/devtools.git tmp/devtools
20
-
21
- if [ -f ".github/workflows/custom_ci.yml" ]; then
22
- rsync -av --exclude '.github/workflows/ci.yml' tmp/devtools/shared/ . ;
23
- else
24
- rsync -av tmp/devtools/shared/ . ;
25
- fi
26
-
27
- git config --local user.email "dry-bot@dry-rb.org"
28
- git config --local user.name "dry-bot"
29
- git add -A
30
- git commit -m "[devtools] config sync" || echo "nothing changed"
31
- - name: Push changes
32
- uses: ad-m/github-push-action@master
33
- with:
34
- github_token: ${{ secrets.GH_PAT }}
data/.gitignore DELETED
@@ -1,12 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
-
10
- # rspec failure tracking
11
- .rspec_status
12
- Gemfile.lock
data/.rspec DELETED
@@ -1,4 +0,0 @@
1
- --color
2
- --require spec_helper
3
- --order random
4
-
data/.rubocop.yml DELETED
@@ -1,95 +0,0 @@
1
- # this file is managed by dry-rb/devtools project
2
-
3
- AllCops:
4
- TargetRubyVersion: 2.4
5
-
6
- Style/EachWithObject:
7
- Enabled: false
8
-
9
- Style/StringLiterals:
10
- Enabled: true
11
- EnforcedStyle: single_quotes
12
-
13
- Style/Alias:
14
- Enabled: false
15
-
16
- Style/LambdaCall:
17
- Enabled: false
18
-
19
- Style/StabbyLambdaParentheses:
20
- Enabled: false
21
-
22
- Style/FormatString:
23
- Enabled: false
24
-
25
- Style/Documentation:
26
- Enabled: false
27
-
28
- Layout/SpaceInLambdaLiteral:
29
- Enabled: false
30
-
31
- Layout/MultilineMethodCallIndentation:
32
- Enabled: true
33
- EnforcedStyle: indented
34
-
35
- Metrics/LineLength:
36
- Max: 100
37
-
38
- Metrics/MethodLength:
39
- Max: 22
40
-
41
- Metrics/ClassLength:
42
- Max: 150
43
-
44
- Metrics/AbcSize:
45
- Max: 20
46
-
47
- Metrics/BlockLength:
48
- Enabled: false
49
-
50
- Metrics/CyclomaticComplexity:
51
- Enabled: true
52
- Max: 10
53
-
54
- Lint/BooleanSymbol:
55
- Enabled: false
56
-
57
- Style/AccessModifierDeclarations:
58
- Enabled: false
59
-
60
- Style/BlockDelimiters:
61
- Enabled: false
62
-
63
- Layout/IndentFirstArrayElement:
64
- EnforcedStyle: consistent
65
-
66
- Style/ClassAndModuleChildren:
67
- Exclude:
68
- - "spec/**/*_spec.rb"
69
-
70
- Lint/HandleExceptions:
71
- Exclude:
72
- - "spec/spec_helper.rb"
73
-
74
- Naming/FileName:
75
- Exclude:
76
- - "lib/dry-*.rb"
77
-
78
- Style/SymbolArray:
79
- Exclude:
80
- - "spec/**/*_spec.rb"
81
-
82
- Style/ConditionalAssignment:
83
- Enabled: false
84
-
85
- Naming/MethodName:
86
- Enabled: false
87
-
88
- Style/AsciiComments:
89
- Enabled: false
90
-
91
- Style/DateTime:
92
- Enabled: false
93
-
94
- Style/IfUnlessModifier:
95
- Enabled: false
data/CODE_OF_CONDUCT.md DELETED
@@ -1,13 +0,0 @@
1
- # Contributor Code of Conduct
2
-
3
- As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
-
5
- We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
6
-
7
- Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
-
9
- Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
-
11
- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
-
13
- This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.4.0, available at [https://www.contributor-covenant.org/version/1/4/code-of-conduct](https://www.contributor-covenant.org/version/1/4/code-of-conduct)
data/CONTRIBUTING.md DELETED
@@ -1,29 +0,0 @@
1
- # Issue Guidelines
2
-
3
- ## Reporting bugs
4
-
5
- If you found a bug, report an issue and describe what's the expected behavior versus what actually happens. If the bug causes a crash, attach a full backtrace. If possible, a reproduction script showing the problem is highly appreciated.
6
-
7
- ## Reporting feature requests
8
-
9
- Report a feature request **only after discussing it first on [discourse.dry-rb.org](https://discourse.dry-rb.org)** where it was accepted. Please provide a concise description of the feature, don't link to a discussion thread, and instead summarize what was discussed.
10
-
11
- ## Reporting questions, support requests, ideas, concerns etc.
12
-
13
- **PLEASE DON'T** - use [discourse.dry-rb.org](http://discourse.dry-rb.org) instead.
14
-
15
- # Pull Request Guidelines
16
-
17
- A Pull Request will only be accepted if it addresses a specific issue that was reported previously, or fixes typos, mistakes in documentation etc.
18
-
19
- Other requirements:
20
-
21
- 1) Do not open a pull request if you can't provide tests along with it. If you have problems writing tests, ask for help in the related issue.
22
- 2) Follow the style conventions of the surrounding code. In most cases, this is standard ruby style.
23
- 3) Add API documentation if it's a new feature
24
- 4) Update API documentation if it changes an existing feature
25
- 5) Bonus points for sending a PR to [github.com/dry-rb/dry-rb.org](github.com/dry-rb/dry-rb.org) which updates user documentation and guides
26
-
27
- # Asking for help
28
-
29
- If these guidelines aren't helpful, and you're stuck, please post a message on [discourse.dry-rb.org](https://discourse.dry-rb.org) or join [our chat](https://dry-rb.zulipchat.com).
data/Gemfile DELETED
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- git_source(:github) { |repo_name| "https://github.com/dry-rb/#{repo_name}" }
6
-
7
- gemspec
8
-
9
- group :test do
10
- gem 'dry-auto_inject', require: false
11
- gem 'dry-system', github: 'dry-system', branch: 'master', require: false
12
- gem 'simplecov', require: false, platform: :mri
13
- gem 'warning'
14
- end
15
-
16
- group :tools do
17
- gem 'pry-byebug', platform: :mri
18
- gem 'rubocop'
19
- gem 'ossy', git: 'https://github.com/solnic/ossy.git', branch: 'master'
20
- end
21
-
22
- gem 'dry-struct'
23
- gem 'dry-monads'
data/Rakefile DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
-
6
- RSpec::Core::RakeTask.new(:spec)
7
-
8
- task default: :spec
@@ -1,84 +0,0 @@
1
- ---
2
- title: Cache
3
- layout: gem-single
4
- name: dry-effects
5
- ---
6
-
7
- Cache provides two interfaces for caching. Set up a handler:
8
-
9
- ```ruby
10
- require 'dry/effects'
11
-
12
- class CacheMiddleware
13
- # Providing scope is required
14
- # All cache values will be scoped with this key
15
- include Dry::Effects::Handler.Cache(:blog)
16
-
17
- def initialize(app)
18
- @app = app
19
- end
20
-
21
- def call(env)
22
- with_cache { @app.env }
23
- end
24
- end
25
- ```
26
-
27
- Using `prepend`:
28
-
29
- ```ruby
30
- require 'dry/effects'
31
-
32
- class ShowUsers
33
- include Dry::Effects.Resolve(:user_repo)
34
- # It will cache .find_user calls
35
- # Users with the same id won't be searched twice
36
- # Effectively (no pun intended),
37
- # it's `memoize` scoped with the call in CacheMiddleware
38
- prepend Dry::Effects.Cache(blog: :find_user)
39
-
40
- def call(user_ids)
41
- users = user_ids.map { find_user(id) }
42
- # ...
43
- end
44
-
45
- def find_user(id)
46
- user_repo.find(id)
47
- end
48
- end
49
- ```
50
-
51
- Or using `include`:
52
-
53
- ```ruby
54
- require 'dry/effects'
55
-
56
- class ShowUsers
57
- include Dry::Effects.Resolve(:user_repo)
58
- # When included, adds #cache method
59
- include Dry::Effects.Cache(:blog)
60
-
61
- def call(user_ids)
62
- users = user_ids.map { cache(:user, id) { user_repo.find(id) } }
63
- # ...
64
- end
65
- end
66
- ```
67
-
68
- ### Cache longevity
69
-
70
- The default cache handler doesn't (yet) support long-lived storage. Cache values are discarded once `with_cache` returns.
71
-
72
- ### Using in tests
73
-
74
- It's usually OK to have a global handler for cache effects:
75
-
76
- ```ruby
77
- require 'dry/effects'
78
-
79
- with_cache = Object.new.extend(Dry::Effects::Handler.Cache(:my_app, as: :call))
80
-
81
- RSpec.configure do |config|
82
- config.around(:each) { with_cache.(&ex) }
83
- end
84
- ```
@@ -1,186 +0,0 @@
1
- ---
2
- title: Current Time
3
- layout: gem-single
4
- name: dry-effects
5
- ---
6
-
7
- Obtaining the current time with `Time.now` is a classic example of a side effect. Code relying on accessing system time is harder to test. One possible solution is passing time around explicitly, but using effects can save you some typing depending on the case.
8
-
9
- Providing and obtaining the current time is straightforward:
10
-
11
- ```ruby
12
- require 'dry/effects'
13
-
14
- class CurrentTimeMiddleware
15
- include Dry::Effects::Handler.CurrentTime
16
-
17
- def initialize(app)
18
- @app = app
19
- end
20
-
21
- def call(env)
22
- # It will use Time.now internally once and set it fixed
23
- with_current_time do
24
- @app.(env)
25
- end
26
- end
27
- end
28
-
29
- ###
30
-
31
- class CreateSubscription
32
- include Dry::Efefcts.Resolve(:subscription_repo)
33
- include Dry::Effects.CurrentTime
34
-
35
- def call(values)
36
- subscription_repo.create(
37
- values.merge(start_at: current_time)
38
- )
39
- end
40
- end
41
- ```
42
-
43
- ### Providing time in tests
44
-
45
- A typical usage would be:
46
-
47
- ```ruby
48
- require 'dry/effects'
49
-
50
- RSpec.configure do |config|
51
- config.include Dry::Effects::Handler.CurrentTime
52
- config.include Dry::Effects.CurrentTime
53
-
54
- config.around { |ex| with_current_time(&ex) }
55
- end
56
- ```
57
-
58
- Then anywhere in tests, you can use it:
59
-
60
- ```ruby
61
- it 'uses current time as a start' do
62
- subscription = create_subscription(...)
63
- expect(subscription.start_at).to eql(current_time)
64
- end
65
- ```
66
-
67
- To change the time, call `with_current_time` with a proc:
68
-
69
- ```ruby
70
- it 'closes a subscription with current time' do
71
- future = current_time + 86_400
72
- closed_subscription = with_current_time(proc { future }) { close_subscription(subscription) }
73
- expect(closed_subscription.closed_at).to eql(future)
74
- end
75
- ```
76
-
77
- Wrapping time with a proc is required, read about generators below.
78
-
79
- ### Time rounding
80
-
81
- `current_time` accepts an argument for rounding time values. It can be passed statically to the module builder or dynamically to the effect constructor:
82
-
83
- ```ruby
84
- class CreateSubscription
85
- include Dry::Effects.CurrentTime(round: 3)
86
-
87
- def call(...)
88
- # value will be rounded to milliseconds
89
- current_time
90
- # value will be rounded to microseconds
91
- current_time(round: 6)
92
- end
93
- end
94
- ```
95
-
96
- ### Time is fixed
97
-
98
- By default, calling `with_current_time` even without arguments will freeze the current time. This means `current_time` will return the same value during request processing etc.
99
-
100
- You can "unfix" time with passing `fixed: false` to the handler builder:
101
-
102
- ```ruby
103
- include Dry::Effects::Handler.CurrentTime(fixed: false)
104
- ```
105
-
106
- However, this is not recommended because it will make the behavior of `current_time` different in tests (where you pass a fixed value) and in a production environment.
107
-
108
- ### Using a custom generator
109
-
110
- The default time provider accepts a custom generator which is a simple callable object. This way you can pass a proc with fixed time:
111
-
112
- ```ruby
113
- frozen = Time.now
114
- with_fixed_time(proc { frozen }) do
115
- # ...
116
- end
117
- ```
118
-
119
- Or you can change time on every call:
120
-
121
- ```ruby
122
- start = Time.now
123
- with_fixed_time(proc { start += 0.1 }) do
124
- # ...
125
- end
126
- ```
127
-
128
- ### Discrete time shifts
129
-
130
- If you pass `step: x` to the handler, it will shift the current time on every access by `x`:
131
-
132
- ```ruby
133
- with_fixed_time(step: 0.1) do
134
- current_time # => ... 18:00:00.000
135
- current_time # => ... 18:00:00.100
136
- current_time # => ... 18:00:00.200
137
- end
138
- ```
139
-
140
- You can also pass initial time:
141
-
142
- ```ruby
143
- initial = Time.new(1970)
144
- with_fixed_time(initial: initial, step: 60) do
145
- current_time # => 1970-01-01 00:00:00 +0000
146
- current_time # => 1970-01-01 00:01:00 +0000
147
- current_time # => 1970-01-01 00:02:00 +0000
148
- end
149
- ```
150
-
151
- ### Overriding handlers
152
-
153
- Handlers of current time can be overridden by an outer handler if you pass `overridable: true`:
154
-
155
- ```ruby
156
- require 'dry/effects'
157
-
158
- class CurrentTimeMiddleware
159
- include Dry::Effects::Handler.CurrentTime
160
-
161
- def initialize(app)
162
- @app = app
163
- end
164
-
165
- def call(env)
166
- with_current_time(overridable: ENV['RACK_ENV'].eql?('test')) do
167
- @app.(env)
168
- end
169
- end
170
- end
171
- ```
172
-
173
- It's usually done in tests:
174
-
175
- ```ruby
176
- # Using global time
177
- frozen_time = Time.now
178
-
179
- puts "Running with time #{frozen_time.iso8601}" if ENV['CI']
180
-
181
- RSpec.configure do |config|
182
- config.include Dry::Effects::Handler.CurrentTime
183
- config.include(Module.new { define_method(:current_time) { frozen_time } })
184
- config.around { |ex| with_current_time(proc { frozen_time }, &ex) }
185
- end
186
- ```