├── var ├── name ├── title ├── version ├── created ├── license ├── organization ├── summary ├── authors ├── copyrights ├── repositories ├── requirements ├── description └── resources ├── lib ├── fluidity.yml ├── fluidity.rb └── fluidity │ ├── is.rb │ ├── about.rb │ ├── assert.rb │ ├── should.rb │ ├── will.rb │ ├── must.rb │ └── grammer.rb ├── demo ├── 00_intro.md ├── 04_other.md ├── 01_should.md ├── 02_must.md └── 03_assert.md ├── Gemfile ├── .ruby ├── .gitignore ├── .travis.yml ├── Config.rb ├── HISTORY.md ├── MANIFEST ├── Assembly ├── LICENSE.txt ├── .index ├── README.md └── .gemspec /var/name: -------------------------------------------------------------------------------- 1 | fluidity 2 | -------------------------------------------------------------------------------- /var/title: -------------------------------------------------------------------------------- 1 | Fluidity 2 | -------------------------------------------------------------------------------- /var/version: -------------------------------------------------------------------------------- 1 | 0.1.1 2 | -------------------------------------------------------------------------------- /lib/fluidity.yml: -------------------------------------------------------------------------------- 1 | ../.index -------------------------------------------------------------------------------- /var/created: -------------------------------------------------------------------------------- 1 | 2012-01-18 2 | -------------------------------------------------------------------------------- /var/license: -------------------------------------------------------------------------------- 1 | BSD-2-Clause 2 | -------------------------------------------------------------------------------- /var/organization: -------------------------------------------------------------------------------- 1 | Rubyworks -------------------------------------------------------------------------------- /var/summary: -------------------------------------------------------------------------------- 1 | Fluid Validity 2 | -------------------------------------------------------------------------------- /demo/00_intro.md: -------------------------------------------------------------------------------- 1 | # Fluidity 2 | 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | gemspec 3 | -------------------------------------------------------------------------------- /var/authors: -------------------------------------------------------------------------------- 1 | --- 2 | - Thomas Sawyer 3 | -------------------------------------------------------------------------------- /.ruby: -------------------------------------------------------------------------------- 1 | ruby 1.9.3p327 (2012-11-10 revision 37606) [x86_64-linux] 2 | -------------------------------------------------------------------------------- /var/copyrights: -------------------------------------------------------------------------------- 1 | --- 2 | - Copyright (c) 2012 Thomas Sawyer (BSD-2-Clause) 3 | -------------------------------------------------------------------------------- /var/repositories: -------------------------------------------------------------------------------- 1 | --- 2 | upstream: git@github.com:rubyworks/fluidity.git 3 | -------------------------------------------------------------------------------- /var/requirements: -------------------------------------------------------------------------------- 1 | --- 2 | - assay 3 | - detroit (build) 4 | - qed (test) 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .reap/digest 2 | .yardoc 3 | log 4 | pkg 5 | tmp 6 | site 7 | web 8 | work/trash 9 | *.lock 10 | DEMOS.* 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | script: "bundle exec qed" 3 | rvm: 4 | - 1.9.2 5 | - 1.9.3 6 | - rbx-19mode 7 | - jruby-19mode 8 | 9 | -------------------------------------------------------------------------------- /lib/fluidity.rb: -------------------------------------------------------------------------------- 1 | require 'fluidity/about' 2 | require 'fluidity/grammer' 3 | require 'fluidity/should' 4 | require 'fluidity/must' 5 | require 'fluidity/assert' 6 | 7 | -------------------------------------------------------------------------------- /var/description: -------------------------------------------------------------------------------- 1 | Fluidity is a test assertions framework built on top of the Assay assertions 2 | meta-framework. It provides an elegant fluid notation for specifying test assertions. 3 | -------------------------------------------------------------------------------- /var/resources: -------------------------------------------------------------------------------- 1 | --- 2 | home: http://rubyworks.github.com/fluidity 3 | docs: http://rubydoc.info/gems/fluidity 4 | code: http://github.com/rubyworks/fluidity 5 | mail: http://groups.google.com/groups/rubyworks-mailinglist 6 | 7 | -------------------------------------------------------------------------------- /Config.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | profile :cov do 4 | 5 | # 6 | # Setup QED. 7 | # 8 | config :qed do 9 | require 'simplecov' 10 | SimpleCov.start do 11 | coverage_dir 'log/coverage' 12 | #add_group "RSpec", "lib/assay/rspec.rb" 13 | end 14 | end 15 | 16 | end 17 | 18 | -------------------------------------------------------------------------------- /lib/fluidity/is.rb: -------------------------------------------------------------------------------- 1 | require 'fluidity/grammer' 2 | 3 | class Object #BasicObject 4 | 5 | # Use `is` nomenclature for assertions. 6 | # 7 | # 10.is.kind_of?(Integer) 8 | # 9 | def is(matcher=nil) 10 | if matcher 11 | matcher === self 12 | else 13 | ::Fluidity::Grammer::Is.new(self) 14 | end 15 | end 16 | 17 | end 18 | 19 | -------------------------------------------------------------------------------- /lib/fluidity/about.rb: -------------------------------------------------------------------------------- 1 | module Fluidity 2 | 3 | # Access to project metadata as constants. 4 | def self.const_missing(name) 5 | key = name.to_s.downcase 6 | index[key] || super(name) 7 | end 8 | 9 | # Access to project metadata. 10 | def self.index 11 | @metadata ||= ( 12 | require 'yaml' 13 | YAML.load_file(File.dirname(__FILE__) + '/../fluidity.yml') 14 | ) 15 | end 16 | 17 | end 18 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # HISTORY 2 | 3 | ## 0.1.1 / 2012-12-21 4 | 5 | Fix bug in #assert nomenclature method, and add support for 6 | both #shouldnt and #musnt in their respective files. 7 | 8 | Changes: 9 | 10 | * Fix matcher check in #assert. 11 | * Add #shouldnt as alias for #should_not. 12 | * Add #musnt as alias for #must_not. 13 | 14 | 15 | ## 0.1.0 / 2012-01-27 16 | 17 | This is the initial release of Fluidity. 18 | 19 | Changes: 20 | 21 | * Happy Birthday! 22 | 23 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | #!mast .index .ruby .yardopts bin demo lib share spec test [A-Z]*.* 2 | .index 3 | .ruby 4 | demo/00_intro.md 5 | demo/01_should.md 6 | demo/02_must.md 7 | demo/03_assert.md 8 | demo/04_other.md 9 | lib/fluidity/about.rb 10 | lib/fluidity/assert.rb 11 | lib/fluidity/grammer.rb 12 | lib/fluidity/is.rb 13 | lib/fluidity/must.rb 14 | lib/fluidity/should.rb 15 | lib/fluidity/will.rb 16 | lib/fluidity.rb 17 | lib/fluidity.yml 18 | LICENSE.txt 19 | HISTORY.md 20 | README.md 21 | DEMOS.md 22 | -------------------------------------------------------------------------------- /Assembly: -------------------------------------------------------------------------------- 1 | --- 2 | github: 3 | gh_pages: web 4 | 5 | gem: 6 | active: true 7 | 8 | dnote: 9 | title: Source Notes 10 | output: log/notes.html 11 | 12 | vclog: 13 | output: 14 | - log/history.html 15 | - log/changes.html 16 | 17 | email: 18 | mailto: 19 | - ruby-talk@ruby-lang.org 20 | - rubyworks-mailinglist@googlegroups.com 21 | 22 | qed: 23 | files: demo 24 | 25 | qedoc: 26 | files: demo 27 | title: Fluidity 28 | output: 29 | - DEMOS.md 30 | - web/demos.html 31 | 32 | -------------------------------------------------------------------------------- /lib/fluidity/assert.rb: -------------------------------------------------------------------------------- 1 | require 'fluidity/grammer' 2 | 3 | class Object 4 | 5 | # Use `assert` nomenclature for assertions. 6 | # 7 | # 10.assert.kind_of?(Integer) 8 | # 9 | def assert(matcher=nil, *args, &blk) 10 | if matcher 11 | if matcher.respond_to?(:=~) # good enough ? 12 | matcher =~ self 13 | else 14 | super(matcher, *args, &blk) 15 | end 16 | else 17 | ::Fluidity::Grammer::Assert.new(self) 18 | end 19 | end 20 | 21 | end 22 | 23 | 24 | module Kernel 25 | public :assert 26 | public :refute 27 | end 28 | -------------------------------------------------------------------------------- /demo/04_other.md: -------------------------------------------------------------------------------- 1 | ## Other Stuff 2 | 3 | What if there is an assertion made for which no Assay class exists? 4 | If the target object has a query method defined by the same name, 5 | that is, one ending in a `?` mark, then that mehtod will be used 6 | to test the assertion. 7 | 8 | c = Class.new do 9 | def initialize(truth) 10 | @truth = truth 11 | end 12 | def yes? 13 | @truth 14 | end 15 | def no? 16 | !@truth 17 | end 18 | end 19 | 20 | x = c.new(true) 21 | 22 | x.should.be.yes 23 | 24 | x.should_not.be.no 25 | 26 | -------------------------------------------------------------------------------- /lib/fluidity/should.rb: -------------------------------------------------------------------------------- 1 | require 'fluidity/grammer' 2 | 3 | class Object #BasicObject 4 | 5 | # Use `should` nomenclature for assertions. 6 | # 7 | # 10.should.be.kind_of(Integer) 8 | # 9 | def should(matcher=nil) 10 | if matcher 11 | matcher =~ self 12 | else 13 | ::Fluidity::Grammer::Should.new(self) 14 | end 15 | end 16 | 17 | # Also, `should_not` nomenclature for assertions. 18 | # 19 | # 10.should_not.be.kind_of?(Integer) 20 | # 21 | def should_not(matcher=nil) 22 | if matcher 23 | matcher !~ self 24 | else 25 | ::Fluidity::Grammer::Should.new(self, true) 26 | end 27 | end 28 | 29 | alias_method :shouldnt, :should_not 30 | 31 | end 32 | 33 | -------------------------------------------------------------------------------- /lib/fluidity/will.rb: -------------------------------------------------------------------------------- 1 | require 'fluidity/grammer' 2 | 3 | class Object #BasicObject 4 | 5 | # Use `will` nomenclature for assertions. 6 | # 7 | # 10.will.be.kind_of(Integer) 8 | # 9 | def will(matcher=nil) 10 | if matcher 11 | matcher =~ self 12 | else 13 | ::Fluidity::Grammer::Must.new(self) 14 | end 15 | end 16 | 17 | # Also, `will_not` nomenclature for assertions. 18 | # 19 | # 10.will_not.be.kind_of?(Integer) 20 | # 21 | def must_not(matcher=nil) 22 | if matcher 23 | matcher !~ self 24 | else 25 | ::Fluidity::Grammer::Must.new(self, true) 26 | end 27 | end 28 | 29 | # Contraction of will not. 30 | # 31 | # 10.wont.be.kind_of?(Integer) 32 | # 33 | alias_method :wont, :will_not 34 | 35 | end 36 | 37 | -------------------------------------------------------------------------------- /lib/fluidity/must.rb: -------------------------------------------------------------------------------- 1 | require 'fluidity/grammer' 2 | 3 | # TODO: What about BasicObject ? 4 | 5 | class Object #BasicObject 6 | 7 | # Use `must` nomenclature for assertions. 8 | # 9 | # 10.must.be.kind_of(Integer) 10 | # 11 | def must(matcher=nil) 12 | if matcher 13 | matcher =~ self 14 | else 15 | ::Fluidity::Grammer::Must.new(self) 16 | end 17 | end 18 | 19 | # Also, `must_not` nomenclature for assertions. 20 | # 21 | # 10.must_not.be.kind_of?(Integer) 22 | # 23 | def must_not(matcher=nil) 24 | if matcher 25 | matcher !~ self 26 | else 27 | ::Fluidity::Grammer::Must.new(self, true) 28 | end 29 | end 30 | 31 | # Contraction do must not. 32 | # 33 | # 10.mustnt.be.kind_of?(Integer) 34 | # 35 | alias_method :mustnt, :must_not 36 | 37 | end 38 | 39 | -------------------------------------------------------------------------------- /demo/01_should.md: -------------------------------------------------------------------------------- 1 | ## Should 2 | 3 | require 'fluidity/should' 4 | 5 | Now we have a fluent notation with which to make assertions. 6 | 7 | true.should.be.true 8 | false.should.be.false 9 | 10 | (5 + 5).should.equal 10 11 | 12 | [1,2,3].should.include(2) 13 | 14 | We can also use the associated operator (Ruby's built-in query method name). 15 | 16 | false.should.be.false? 17 | true.should.be.true? 18 | 19 | (5 + 5).should == 10 20 | 21 | Indefinite article `a` and `an` are suppored. 22 | 23 | 12.should.be.a.kind_of?(Integer) 24 | 25 | As is `not` for negation. 26 | 27 | 12.should.not.equal(20) 28 | 29 | We should also make sure such assertions can fail. 30 | 31 | IncludeAssay.should.be.raised do 32 | [1,2,3].should.include(4) 33 | end 34 | 35 | FalseAssay.should.be.raised do 36 | true.should.be.false 37 | end 38 | 39 | EqualAssay.should.be.raised do 40 | (5 + 5).should == 11 41 | end 42 | 43 | Matcher notation is also supported, if you have any matcher classes 44 | to use. Assay classes can be converted to matchers, so we can use 45 | one of those to try this out. 46 | 47 | be_sixteen = EqualAssay[16.0] 48 | 49 | 16.should be_sixteen 50 | 51 | 15.should_not be_sixteen 52 | 53 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD-2-Clause License 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 14 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 15 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 16 | COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 17 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 20 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 22 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /.index: -------------------------------------------------------------------------------- 1 | --- 2 | type: ruby 3 | revision: 2013 4 | sources: 5 | - var 6 | authors: 7 | - name: Thomas Sawyer 8 | email: transfire@gmail.com 9 | organizations: [] 10 | requirements: 11 | - name: assay 12 | - groups: 13 | - build 14 | development: true 15 | name: detroit 16 | - groups: 17 | - test 18 | development: true 19 | name: qed 20 | conflicts: [] 21 | alternatives: [] 22 | resources: 23 | - type: home 24 | uri: http://rubyworks.github.com/fluidity 25 | label: Homepage 26 | - type: docs 27 | uri: http://rubydoc.info/gems/fluidity 28 | label: Documentation 29 | - type: code 30 | uri: http://github.com/rubyworks/fluidity 31 | label: Source Code 32 | - type: mail 33 | uri: http://groups.google.com/groups/rubyworks-mailinglist 34 | label: Mailing List 35 | repositories: 36 | - name: upstream 37 | scm: git 38 | uri: git@github.com:rubyworks/fluidity.git 39 | categories: [] 40 | paths: 41 | load: 42 | - lib 43 | copyrights: 44 | - holder: Thomas Sawyer 45 | year: '2012' 46 | license: BSD-2-Clause 47 | created: '2012-01-18' 48 | summary: Fluid Validity 49 | title: Fluidity 50 | version: 0.1.1 51 | name: fluidity 52 | description: ! 'Fluidity is a test assertions framework built on top of the Assay 53 | assertions 54 | 55 | meta-framework. It provides an elegant fluid notation for specifying test assertions.' 56 | date: '2012-12-21' 57 | -------------------------------------------------------------------------------- /demo/02_must.md: -------------------------------------------------------------------------------- 1 | ## Must 2 | 3 | require 'fluidity/must' 4 | 5 | Now we have a fluent notation with which to make assertions. 6 | 7 | true.must.be.true 8 | false.must.be.false 9 | 10 | (5 + 5).must.equal 10 11 | 12 | [1,2,3].must.include(2) 13 | 14 | We can also use the associated operator (Ruby's built-in query method name). 15 | 16 | false.must.be.false? 17 | true.must.be.true? 18 | 19 | (5 + 5).must == 10 20 | 21 | Indefinite article `a` and `an` are suppored. 22 | 23 | 12.must.be.a.kind_of?(Integer) 24 | 25 | 12.must.be.an.instance_of?(Fixnum) 26 | 27 | As is `not` for negation. 28 | 29 | 12.must.not.equal(20) 30 | 31 | Or `must_not` can also be used. 32 | 33 | 12.must_not.equal(20) 34 | 35 | We must also make sure such assertions can fail. 36 | 37 | IncludeAssay.must.be.raised do 38 | [1,2,3].must.include(4) 39 | end 40 | 41 | FalseAssay.must.be.raised do 42 | true.must.be.false 43 | end 44 | 45 | EqualAssay.must.be.raised do 46 | (5 + 5).must == 11 47 | end 48 | 49 | Matcher notation is also supported, if you have any matcher classes 50 | to use. Assay classes can be converted to matchers, so we can use 51 | one of those to try this out. 52 | 53 | be_sixteen = EqualAssay[16.0] 54 | 55 | 16.must be_sixteen 56 | 57 | 15.must_not be_sixteen 58 | 59 | -------------------------------------------------------------------------------- /demo/03_assert.md: -------------------------------------------------------------------------------- 1 | ## Grammer 2 | 3 | require 'fluidity/assert' 4 | 5 | Now we have a fluent notation with which to make assertions. 6 | 7 | true.assert.true 8 | false.assert.false 9 | 10 | (5 + 5).must.equal 10 11 | 12 | [1,2,3].must.include(2) 13 | 14 | We can also use the associated operator (Ruby's built-in query method name). 15 | 16 | false.assert.false? 17 | true.assert.true? 18 | 19 | (5 + 5).assert == 10 20 | 21 | (9 + 9).assert.not == 10 22 | 23 | 12.assert.kind_of?(Integer) 24 | 25 | As is `not` for negation. 26 | 27 | 12.assert.not.equal(20) 28 | 29 | Or `should_not` can also be used. 30 | 31 | 12.should_not.equal(20) 32 | 33 | We must also make sure such assertions can fail. Since #assert is special 34 | method to assay classes, we can use it as on these as part of our test 35 | grmmer. So we use the raw `#assert!` method to handle the test. 36 | 37 | RaiseAssay.assert!(IncludeAssay) do 38 | [1,2,3].assert.include(4) 39 | end 40 | 41 | RaiseAssay.assert!(FalseAssay) do 42 | true.assert.false 43 | end 44 | 45 | RaiseAssay.assert!(EqualityAssay) do 46 | (5 + 5).assert == 11 47 | end 48 | 49 | Matcher notation is also supported, if you have any matcher classes 50 | to use. Assay classes can be converted to matchers, so we can use 51 | one of those to try this out. 52 | 53 | is_sixteen = EqualityAssay[16.0] 54 | 55 | 16.assert is_sixteen 56 | 57 | -------------------------------------------------------------------------------- /lib/fluidity/grammer.rb: -------------------------------------------------------------------------------- 1 | require 'assay' 2 | 3 | module Fluidity 4 | 5 | module Grammer 6 | 7 | class Base 8 | 9 | def initialize(target, negate=false) 10 | @target = target 11 | @negate = negate 12 | end 13 | 14 | # Have to override the ususal `#==` method to support this. 15 | def ==(other) 16 | if @negate 17 | ::EqualAssay.refute!(@target, other, :backtrace=>caller) 18 | else 19 | ::EqualAssay.assert!(@target, other, :backtrace=>caller) 20 | end 21 | end 22 | 23 | #private 24 | 25 | def method_missing(s, *a, &b) 26 | if assay = (::Assertion.by_name(s) || ::Assertion.by_operator(s)) 27 | if @negate 28 | assay.refute!(@target, *a, &b) 29 | else 30 | assay.assert!(@target, *a, &b) 31 | end 32 | else 33 | q = (s.to_s.end_with?('?') ? s : (s.to_s+'?')) 34 | if @target.respond_to?(q) 35 | assert(false, "#{q} failed", caller) unless @target.send(q, *a, &b) 36 | else 37 | super(s, *a, &b) 38 | end 39 | end 40 | end 41 | 42 | end 43 | 44 | # 45 | class Assert < Base 46 | 47 | #def method_missing(s, *a, &b) 48 | # call(s, *a, &b) 49 | #end 50 | 51 | def not 52 | Assert.new(@target, !@negate) 53 | end 54 | 55 | end 56 | 57 | # 58 | class Be < Base 59 | 60 | #def method_missing(s, *a, &b) 61 | # call(s, *a, &b) 62 | #end 63 | 64 | # 65 | def a 66 | self 67 | end 68 | 69 | # 70 | def an 71 | self 72 | end 73 | 74 | end 75 | 76 | # 77 | class Is < Be 78 | 79 | def not 80 | Is.new(@target, !@negate) 81 | end 82 | 83 | end 84 | 85 | # 86 | class Must < Base 87 | 88 | #def method_missing(s, *a, &b) 89 | # call(s, *a, &b) 90 | #end 91 | 92 | def be 93 | Be.new(@target, @negate) 94 | end 95 | 96 | def not 97 | Must.new(@target, !@negate) 98 | end 99 | 100 | end 101 | 102 | # 103 | class Should < Base 104 | 105 | #def method_missing(s, *a, &b) 106 | # call(s, *a, &b) 107 | #end 108 | 109 | def be 110 | Be.new(@target, @negate) 111 | end 112 | 113 | def not 114 | Should.new(@target, !@negate) 115 | end 116 | 117 | end 118 | 119 | end 120 | 121 | end 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fluidity 2 | 3 | [Website](http://rubyworks.github.com/fluidity) / 4 | [Report Issue](http://github.com/rubyworks/fluidity/issues) / 5 | [Source Code](http://github.com/rubyworks/fluidity) 6 | ( [![Build Status](https://secure.travis-ci.org/rubyworks/fluidity.png)](http://travis-ci.org/rubyworks/fluidity) ) 7 | 8 |
9 | 10 | Fluidity is an assertions framework that provides a very elegant fluid 11 | notation for specifying test assertions. 12 | 13 | Fluidity is built on top of the [Assay](http://rubyworks.github.com/assay) 14 | assertions meta-framework, giving it a solid foundation. Assay defines 15 | assertions in the same way that Ruby defines exceptions. Assay provides 16 | a complete set of these assertion classes for all common assertion needs. 17 | 18 | 19 | ## Instruction 20 | 21 | Developers want to write assertions easily and concisely. To this end Fluidity 22 | provides a flexible grammar system which can be used by requiring any of the 23 | prime grammar methods that extend Object. The most common is probably `should`. 24 | 25 | require 'fluidity/should' 26 | 27 | 10.should.be.kind_of(Integer) 28 | 29 | But if you are accustom to MiniTest's spec methods, you might prefer `must`. 30 | 31 | require 'fluidity/must' 32 | 33 | 10.must.be.kind_of(Integer) 34 | 35 | Also provided is `assert` for those techy aficionados. 36 | 37 | require 'fluidity/assert' 38 | 39 | 10.assert.kind_of(Integer) 40 | 41 | So what is so fluid about all this? Well, Fluidity allows the developer quite 42 | the English like expression. For instance. 43 | 44 | 10.should.not.be.an.instance_of?(String) 45 | 46 | Pretty neat, though perhaps bit excessive for a real-life use. Generally 47 | it's good enough to use the shorter and a tad bit faster: 48 | 49 | 10.shouldnt.be.instance_of?(String) 50 | 51 | Speaking of _fast_, so what about speed? Of course, running through multiple 52 | extra method calls to make an assertion is going to be slower than making just 53 | a single method call. So, yes, tests might run a bit slower on Fluidity than 54 | they would with another less readable assertions system. However, method calls 55 | are pretty dang fast and unlikely to present any significant performance 56 | overhead on test runs. At most, tests runs might take a few additional seconds 57 | for _very_ _large_ test suites. 58 | 59 | 60 | ## Installation 61 | 62 | To install with RubyGems simply open a console and type: 63 | 64 | gem install fluidity 65 | 66 | Site installation with the tarball can be done with Ruby Setup 67 | (gem install setup). See http://rubyworks.github.com/setup. 68 | 69 | 70 | ## Copyrights 71 | 72 | Fluidity is copyrighted open source software. 73 | 74 | Copyright (c) 2012 Rubyworks 75 | 76 | This program can be modified and distributed in accordance with 77 | the terms of the [BSD-2-Clause](http://spdx.org/licenses/BSD-2-Clause) license. 78 | 79 | See LICENSE.txt file for details. 80 | -------------------------------------------------------------------------------- /.gemspec: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'yaml' 4 | require 'pathname' 5 | 6 | module Indexer 7 | 8 | # Convert index data into a gemspec. 9 | # 10 | # Notes: 11 | # * Assumes all executables are in bin/. 12 | # * Does not yet handle default_executable setting. 13 | # * Does not yet handle platform setting. 14 | # * Does not yet handle required_ruby_version. 15 | # * Support for rdoc entries is weak. 16 | # 17 | class GemspecExporter 18 | 19 | # File globs to include in package --unless a manifest file exists. 20 | FILES = ".index .yardopts alt bin data demo ext features lib man spec test try* [A-Z]*.*" unless defined?(FILES) 21 | 22 | # File globs to omit from FILES. 23 | OMIT = "Config.rb" unless defined?(OMIT) 24 | 25 | # Standard file patterns. 26 | PATTERNS = { 27 | :root => '{.index,Gemfile}', 28 | :bin => 'bin/*', 29 | :lib => 'lib/{**/}*', #.rb', 30 | :ext => 'ext/{**/}extconf.rb', 31 | :doc => '*.{txt,rdoc,md,markdown,tt,textile}', 32 | :test => '{test,spec}/{**/}*.rb' 33 | } unless defined?(PATTERNS) 34 | 35 | # For which revision of indexer spec is this converter intended? 36 | REVISION = 2013 unless defined?(REVISION) 37 | 38 | # 39 | def self.gemspec 40 | new.to_gemspec 41 | end 42 | 43 | # 44 | attr :metadata 45 | 46 | # 47 | def initialize(metadata=nil) 48 | @root_check = false 49 | 50 | if metadata 51 | root_dir = metadata.delete(:root) 52 | if root_dir 53 | @root = root_dir 54 | @root_check = true 55 | end 56 | metadata = nil if metadata.empty? 57 | end 58 | 59 | @metadata = metadata || YAML.load_file(root + '.index') 60 | 61 | if @metadata['revision'].to_i != REVISION 62 | warn "This gemspec exporter was not designed for this revision of index metadata." 63 | end 64 | end 65 | 66 | # 67 | def has_root? 68 | root ? true : false 69 | end 70 | 71 | # 72 | def root 73 | return @root if @root || @root_check 74 | @root_check = true 75 | @root = find_root 76 | end 77 | 78 | # 79 | def manifest 80 | return nil unless root 81 | @manifest ||= Dir.glob(root + 'manifest{,.txt}', File::FNM_CASEFOLD).first 82 | end 83 | 84 | # 85 | def scm 86 | return nil unless root 87 | @scm ||= %w{git hg}.find{ |m| (root + ".#{m}").directory? }.to_sym 88 | end 89 | 90 | # 91 | def files 92 | return [] unless root 93 | @files ||= \ 94 | if manifest 95 | File.readlines(manifest). 96 | map{ |line| line.strip }. 97 | reject{ |line| line.empty? || line[0,1] == '#' } 98 | else 99 | list = [] 100 | Dir.chdir(root) do 101 | FILES.split(/\s+/).each do |pattern| 102 | list.concat(glob(pattern)) 103 | end 104 | OMIT.split(/\s+/).each do |pattern| 105 | list = list - glob(pattern) 106 | end 107 | end 108 | list 109 | end.select{ |path| File.file?(path) }.uniq 110 | end 111 | 112 | # 113 | def glob_files(pattern) 114 | return [] unless root 115 | Dir.chdir(root) do 116 | Dir.glob(pattern).select do |path| 117 | File.file?(path) && files.include?(path) 118 | end 119 | end 120 | end 121 | 122 | def patterns 123 | PATTERNS 124 | end 125 | 126 | def executables 127 | @executables ||= \ 128 | glob_files(patterns[:bin]).map do |path| 129 | File.basename(path) 130 | end 131 | end 132 | 133 | def extensions 134 | @extensions ||= \ 135 | glob_files(patterns[:ext]).map do |path| 136 | File.basename(path) 137 | end 138 | end 139 | 140 | def name 141 | metadata['name'] || metadata['title'].downcase.gsub(/\W+/,'_') 142 | end 143 | 144 | def homepage 145 | page = ( 146 | metadata['resources'].find{ |r| r['type'] =~ /^home/i } || 147 | metadata['resources'].find{ |r| r['name'] =~ /^home/i } || 148 | metadata['resources'].find{ |r| r['name'] =~ /^web/i } 149 | ) 150 | page ? page['uri'] : false 151 | end 152 | 153 | def licenses 154 | metadata['copyrights'].map{ |c| c['license'] }.compact 155 | end 156 | 157 | def require_paths 158 | paths = metadata['paths'] || {} 159 | paths['load'] || ['lib'] 160 | end 161 | 162 | # 163 | # Convert to gemnspec. 164 | # 165 | def to_gemspec 166 | if has_root? 167 | Gem::Specification.new do |gemspec| 168 | to_gemspec_data(gemspec) 169 | to_gemspec_paths(gemspec) 170 | end 171 | else 172 | Gem::Specification.new do |gemspec| 173 | to_gemspec_data(gemspec) 174 | to_gemspec_paths(gemspec) 175 | end 176 | end 177 | end 178 | 179 | # 180 | # Convert pure data settings. 181 | # 182 | def to_gemspec_data(gemspec) 183 | gemspec.name = name 184 | gemspec.version = metadata['version'] 185 | gemspec.summary = metadata['summary'] 186 | gemspec.description = metadata['description'] 187 | 188 | metadata['authors'].each do |author| 189 | gemspec.authors << author['name'] 190 | 191 | if author.has_key?('email') 192 | if gemspec.email 193 | gemspec.email << author['email'] 194 | else 195 | gemspec.email = [author['email']] 196 | end 197 | end 198 | end 199 | 200 | gemspec.licenses = licenses 201 | 202 | requirements = metadata['requirements'] || [] 203 | requirements.each do |req| 204 | next if req['optional'] 205 | next if req['external'] 206 | 207 | name = req['name'] 208 | groups = req['groups'] || [] 209 | 210 | version = gemify_version(req['version']) 211 | 212 | if groups.empty? or groups.include?('runtime') 213 | # populate runtime dependencies 214 | if gemspec.respond_to?(:add_runtime_dependency) 215 | gemspec.add_runtime_dependency(name,*version) 216 | else 217 | gemspec.add_dependency(name,*version) 218 | end 219 | else 220 | # populate development dependencies 221 | if gemspec.respond_to?(:add_development_dependency) 222 | gemspec.add_development_dependency(name,*version) 223 | else 224 | gemspec.add_dependency(name,*version) 225 | end 226 | end 227 | end 228 | 229 | # convert external dependencies into gemspec requirements 230 | requirements.each do |req| 231 | next unless req['external'] 232 | gemspec.requirements << ("%s-%s" % req.values_at('name', 'version')) 233 | end 234 | 235 | gemspec.homepage = homepage 236 | gemspec.require_paths = require_paths 237 | gemspec.post_install_message = metadata['install_message'] 238 | end 239 | 240 | # 241 | # Set gemspec settings that require a root directory path. 242 | # 243 | def to_gemspec_paths(gemspec) 244 | gemspec.files = files 245 | gemspec.extensions = extensions 246 | gemspec.executables = executables 247 | 248 | if Gem::VERSION < '1.7.' 249 | gemspec.default_executable = gemspec.executables.first 250 | end 251 | 252 | gemspec.test_files = glob_files(patterns[:test]) 253 | 254 | unless gemspec.files.include?('.document') 255 | gemspec.extra_rdoc_files = glob_files(patterns[:doc]) 256 | end 257 | end 258 | 259 | # 260 | # Return a copy of this file. This is used to generate a local 261 | # .gemspec file that can automatically read the index file. 262 | # 263 | def self.source_code 264 | File.read(__FILE__) 265 | end 266 | 267 | private 268 | 269 | def find_root 270 | root_files = patterns[:root] 271 | if Dir.glob(root_files).first 272 | Pathname.new(Dir.pwd) 273 | elsif Dir.glob("../#{root_files}").first 274 | Pathname.new(Dir.pwd).parent 275 | else 276 | #raise "Can't find root of project containing `#{root_files}'." 277 | warn "Can't find root of project containing `#{root_files}'." 278 | nil 279 | end 280 | end 281 | 282 | def glob(pattern) 283 | if File.directory?(pattern) 284 | Dir.glob(File.join(pattern, '**', '*')) 285 | else 286 | Dir.glob(pattern) 287 | end 288 | end 289 | 290 | def gemify_version(version) 291 | case version 292 | when /^(.*?)\+$/ 293 | ">= #{$1}" 294 | when /^(.*?)\-$/ 295 | "< #{$1}" 296 | when /^(.*?)\~$/ 297 | "~> #{$1}" 298 | else 299 | version 300 | end 301 | end 302 | 303 | end 304 | 305 | end 306 | 307 | Indexer::GemspecExporter.gemspec --------------------------------------------------------------------------------