зеркало из https://github.com/github/github-ds.git
Initial commit of gem with GitHub::Data::Result
This commit is contained in:
Коммит
8106b7ff1c
|
@ -0,0 +1,9 @@
|
|||
/.bundle/
|
||||
/.yardoc
|
||||
/Gemfile.lock
|
||||
/_yardoc/
|
||||
/coverage/
|
||||
/doc/
|
||||
/pkg/
|
||||
/spec/reports/
|
||||
/tmp/
|
|
@ -0,0 +1,5 @@
|
|||
sudo: false
|
||||
language: ruby
|
||||
rvm:
|
||||
- 2.3.3
|
||||
before_install: gem install bundler -v 1.14.6
|
|
@ -0,0 +1,74 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
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, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at nunemaker@gmail.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -0,0 +1,4 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in github-data.gemspec
|
||||
gemspec
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 John Nunemaker
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,41 @@
|
|||
# Github::Data
|
||||
|
||||
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/github/data`. To experiment with that code, run `bin/console` for an interactive prompt.
|
||||
|
||||
TODO: Delete this and the text above, and describe your gem
|
||||
|
||||
## Installation
|
||||
|
||||
Add this line to your application's Gemfile:
|
||||
|
||||
```ruby
|
||||
gem 'github-data'
|
||||
```
|
||||
|
||||
And then execute:
|
||||
|
||||
$ bundle
|
||||
|
||||
Or install it yourself as:
|
||||
|
||||
$ gem install github-data
|
||||
|
||||
## Usage
|
||||
|
||||
TODO: Write usage instructions here
|
||||
|
||||
## Development
|
||||
|
||||
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
||||
|
||||
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
||||
|
||||
## Contributing
|
||||
|
||||
Bug reports and pull requests are welcome on GitHub at https://github.com/jnunemaker/github-data. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
require "bundler/gem_tasks"
|
||||
require "rake/testtask"
|
||||
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << "test"
|
||||
t.libs << "lib"
|
||||
t.test_files = FileList['test/**/*_test.rb']
|
||||
end
|
||||
|
||||
task :default => :test
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require "bundler/setup"
|
||||
require "github/data"
|
||||
|
||||
# You can add fixtures and/or initialization code here to make experimenting
|
||||
# with your gem easier. You can also use a different console, if you like.
|
||||
|
||||
# (If you use this, don't forget to add pry to your Gemfile!)
|
||||
# require "pry"
|
||||
# Pry.start
|
||||
|
||||
require "irb"
|
||||
IRB.start(__FILE__)
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
set -vx
|
||||
|
||||
bundle install
|
||||
|
||||
# Do any other automated setup that you need to do here
|
|
@ -0,0 +1,36 @@
|
|||
# coding: utf-8
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'github/data/version'
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "github-data"
|
||||
spec.version = Github::Data::VERSION
|
||||
spec.authors = ["John Nunemaker"]
|
||||
spec.email = ["nunemaker@gmail.com"]
|
||||
|
||||
spec.summary = %q{TODO: Write a short summary, because Rubygems requires one.}
|
||||
spec.description = %q{TODO: Write a longer description or delete this line.}
|
||||
spec.homepage = "TODO: Put your gem's website or public repo URL here."
|
||||
spec.license = "MIT"
|
||||
|
||||
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
||||
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
||||
if spec.respond_to?(:metadata)
|
||||
spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
||||
else
|
||||
raise "RubyGems 2.0 or newer is required to protect against " \
|
||||
"public gem pushes."
|
||||
end
|
||||
|
||||
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
||||
f.match(%r{^(test|spec|features)/})
|
||||
end
|
||||
spec.bindir = "exe"
|
||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_development_dependency "bundler", "~> 1.14"
|
||||
spec.add_development_dependency "rake", "~> 10.0"
|
||||
spec.add_development_dependency "minitest", "~> 5.0"
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
require "github/data/version"
|
||||
require "github/data/result"
|
||||
|
||||
module Github
|
||||
module Data
|
||||
# Your code goes here...
|
||||
end
|
||||
end
|
|
@ -0,0 +1,231 @@
|
|||
module GitHub
|
||||
module Data
|
||||
class Result
|
||||
# Invokes the supplied block and wraps the return value in a
|
||||
# GitHub::Data::Result object.
|
||||
#
|
||||
# Exceptions raised by the block are caught and also wrapped.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# GitHub::Data::Result.new { 123 }
|
||||
# # => #<GitHub::Data::Result value: 123>
|
||||
#
|
||||
# GitHub::Data::Result.new { raise "oops" }
|
||||
# # => #<GitHub::Data::Result error: #<RuntimeError: oops>>
|
||||
#
|
||||
def initialize
|
||||
begin
|
||||
@value = yield
|
||||
@error = nil
|
||||
rescue => e
|
||||
@error = e
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
if ok?
|
||||
"#<GitHub::Data::Result:0x%x value: %s>" % [object_id, @value.inspect]
|
||||
else
|
||||
"#<GitHub::Data::Result:0x%x error: %s>" % [object_id, @error.inspect]
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :inspect, :to_s
|
||||
|
||||
# If the result represents a value, invokes the supplied block with
|
||||
# that value.
|
||||
#
|
||||
# If the result represents an error, returns self.
|
||||
#
|
||||
# The block must also return a GitHub::Data::Result object.
|
||||
# Use #map otherwise.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# result = do_something().then { |val|
|
||||
# do_other_thing(val)
|
||||
# }
|
||||
# # => #<GitHub::Data::Result value: ...>
|
||||
#
|
||||
# do_something_that_fails().then { |val|
|
||||
# # never invoked
|
||||
# }
|
||||
# # => #<GitHub::Data::Result error: ...>
|
||||
#
|
||||
def then
|
||||
if ok?
|
||||
result = yield(@value)
|
||||
raise TypeError, "block invoked in GitHub::Data::Result#then did not return GitHub::Data::Result" unless result.is_a?(Result)
|
||||
result
|
||||
else
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
# If the result represents an error, invokes the supplied block with that error.
|
||||
#
|
||||
# If the result represents a value, returns self.
|
||||
#
|
||||
# The block must also return a GitHub::Data::Result object.
|
||||
# Use #map otherwise.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# result = do_something().rescue { |val|
|
||||
# # never invoked
|
||||
# }
|
||||
# # => #<GitHub::Data::Result value: ...>
|
||||
#
|
||||
# do_something_that_fails().rescue { |val|
|
||||
# # handle_error(val)
|
||||
# }
|
||||
# # => #<GitHub::Data::Result error: ...>
|
||||
#
|
||||
def rescue
|
||||
return self if ok?
|
||||
result = yield(@error)
|
||||
raise TypeError, "block invoked in GitHub::Data::Result#rescue did not return GitHub::Data::Result" unless result.is_a?(Result)
|
||||
result
|
||||
end
|
||||
|
||||
# If the result represents a value, invokes the supplied block with that
|
||||
# value and wraps the block's return value in a GitHub::Data::Result.
|
||||
#
|
||||
# If the result represents an error, returns self.
|
||||
#
|
||||
# The block should not return a GitHub::Data::Result object (unless you
|
||||
# truly intend to create a GitHub::Data::Result<GitHub::Data::Result<T>>).
|
||||
# Use #then if it does.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# result = do_something()
|
||||
# # => #<GitHub::Data::Result value: 123>
|
||||
#
|
||||
# result.map { |val| val * 2 }
|
||||
# # => #<GitHub::Data::Result value: 246>
|
||||
#
|
||||
# do_something_that_fails().map { |val|
|
||||
# # never invoked
|
||||
# }
|
||||
# # => #<GitHub::Data::Result error: ...>
|
||||
#
|
||||
def map
|
||||
if ok?
|
||||
Result.new { yield(@value) }
|
||||
else
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
# If the result represents a value, returns that value.
|
||||
#
|
||||
# If the result represents an error, invokes the supplied block with the
|
||||
# exception object.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# result = do_something()
|
||||
# # => #<GitHub::Data::Result value: "foo">
|
||||
#
|
||||
# result.value { "nope" }
|
||||
# # => "foo"
|
||||
#
|
||||
# result = do_something_that_fails()
|
||||
# # => #<GitHub::Data::Result error: ...>
|
||||
#
|
||||
# result.value { "nope" }
|
||||
# # => #<GitHub::Data::Result value: "nope">
|
||||
#
|
||||
def value
|
||||
unless block_given?
|
||||
raise ArgumentError, "must provide a block to GitHub::Data::Result#value to be invoked in case of error"
|
||||
end
|
||||
|
||||
if ok?
|
||||
@value
|
||||
else
|
||||
yield(@error)
|
||||
end
|
||||
end
|
||||
|
||||
# If the result represents a value, returns that value.
|
||||
#
|
||||
# If the result represents an error, raises that error.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# result = do_something()
|
||||
# # => #<GitHub::Data::Result value: "foo">
|
||||
#
|
||||
# result.value!
|
||||
# # => "foo"
|
||||
#
|
||||
# result = do_something_that_fails()
|
||||
# # => #<GitHub::Data::Result error: ...>
|
||||
#
|
||||
# result.value!
|
||||
# # !! raises exception
|
||||
#
|
||||
def value!
|
||||
if ok?
|
||||
@value
|
||||
else
|
||||
raise @error
|
||||
end
|
||||
end
|
||||
|
||||
# Returns true if the result represents a value, false if an error.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# result = do_something()
|
||||
# # => #<GitHub::Data::Result value: "foo">
|
||||
#
|
||||
# result.ok?
|
||||
# # => true
|
||||
#
|
||||
# result = do_something_that_fails()
|
||||
# # => #<GitHub::Data::Result error: ...>
|
||||
#
|
||||
# result.ok?
|
||||
# # => false
|
||||
#
|
||||
def ok?
|
||||
!@error
|
||||
end
|
||||
|
||||
# If the result represents a value, returns nil.
|
||||
#
|
||||
# If the result represents an error, returns that error.
|
||||
#
|
||||
# result = do_something()
|
||||
# # => #<GitHub::Data::Result value: "foo">
|
||||
#
|
||||
# result.error
|
||||
# # => nil
|
||||
#
|
||||
# result = do_something_that_fails()
|
||||
# # => #<GitHub::Data::Result error: ...>
|
||||
#
|
||||
# result.error
|
||||
# # => ...
|
||||
#
|
||||
def error
|
||||
@error
|
||||
end
|
||||
|
||||
# Create a GitHub::Data::Result with only the error condition set.
|
||||
#
|
||||
# GitHub::Data::Result.error(e)
|
||||
# # => # <GitHub::Data::Result error: ...>
|
||||
#
|
||||
def self.error(e)
|
||||
result = allocate
|
||||
result.instance_variable_set(:@error, e)
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
module Github
|
||||
module Data
|
||||
VERSION = "0.1.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,86 @@
|
|||
require 'test_helper'
|
||||
|
||||
class GitHub::Data::ResultTest < Minitest::Test
|
||||
def test_to_s
|
||||
assert_match %r{#<GitHub::Data::Result:0x[a-f0-9]+ value: 123>}, GitHub::Data::Result.new { 123 }.to_s
|
||||
|
||||
assert_match %r{#<GitHub::Data::Result:0x[a-f0-9]+ error: #<RuntimeError: nope>>}, GitHub::Data::Result.new { raise "nope" }.to_s
|
||||
end
|
||||
|
||||
def test_then
|
||||
assert_equal 456, GitHub::Data::Result.new { 123 }.then {
|
||||
GitHub::Data::Result.new { 456 }
|
||||
}.value!
|
||||
|
||||
assert GitHub::Data::Result.new { raise "nope" }.then {
|
||||
flunk "should not have invoked then block"
|
||||
}.error
|
||||
|
||||
assert_raises TypeError do
|
||||
GitHub::Data::Result.new {}.then {
|
||||
"not a result"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def test_rescue
|
||||
assert_equal 456, GitHub::Data::Result.new { raise "nope" }.rescue {
|
||||
GitHub::Data::Result.new { 456 }
|
||||
}.value!
|
||||
|
||||
assert_equal 456, GitHub::Data::Result.new { raise "nope" }.rescue { |error|
|
||||
assert_equal "nope", error.message
|
||||
GitHub::Data::Result.new { 456 }
|
||||
}.value!
|
||||
|
||||
assert GitHub::Data::Result.new { 123 }.rescue {
|
||||
flunk "should not have invoked rescue block"
|
||||
}.value!
|
||||
|
||||
assert_raises TypeError do
|
||||
GitHub::Data::Result.new { raise "nope" }.rescue {
|
||||
"not a result"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def test_map
|
||||
assert_equal 456, GitHub::Data::Result.new { 123 }.map {
|
||||
456
|
||||
}.value!
|
||||
|
||||
assert GitHub::Data::Result.new { raise "nope" }.map {
|
||||
flunk "should not have invoked map block"
|
||||
}.error
|
||||
end
|
||||
|
||||
def test_value
|
||||
assert_equal 123, GitHub::Data::Result.new { 123 }.value { 456 }
|
||||
|
||||
assert_equal 456, GitHub::Data::Result.new { raise "nope" }.value { 456 }
|
||||
end
|
||||
|
||||
def test_value!
|
||||
assert_equal 123, GitHub::Data::Result.new { 123 }.value!
|
||||
|
||||
r = GitHub::Data::Result.new { raise "nope" }
|
||||
|
||||
assert_raises RuntimeError do
|
||||
r.value!
|
||||
end
|
||||
end
|
||||
|
||||
def test_ok?
|
||||
assert_predicate GitHub::Data::Result.new { 123 }, :ok?
|
||||
|
||||
refute_predicate GitHub::Data::Result.new { raise "nope" }, :ok?
|
||||
end
|
||||
|
||||
def test_error
|
||||
assert_nil GitHub::Data::Result.new { 123 }.error
|
||||
|
||||
e = StandardError.new("nope")
|
||||
|
||||
assert_equal e, GitHub::Data::Result.new { raise e }.error
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
require 'test_helper'
|
||||
|
||||
class Github::DataTest < Minitest::Test
|
||||
def test_that_it_has_a_version_number
|
||||
refute_nil ::Github::Data::VERSION
|
||||
end
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
||||
require 'github/data'
|
||||
|
||||
require 'minitest/autorun'
|
Загрузка…
Ссылка в новой задаче