mshakhan-fruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
+ Version 2, December 2004
3
+
4
+ Copyright (C) 2004 Sam Hocevar
5
+ 14 rue de Plaisance, 75014 Paris, France
6
+ Everyone is permitted to copy and distribute verbatim or modified
7
+ copies of this license document, and changing it is allowed as long
8
+ as the name is changed.
9
+
10
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
+
13
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
14
+
15
+ http://sam.zoy.org/wtfpl/COPYING
@@ -0,0 +1,18 @@
1
+ == Description
2
+
3
+ Some functional programming features for ruby.
4
+
5
+ == Usage
6
+
7
+ Now implemented only *defun* method. You can use it like this:
8
+
9
+ module Math
10
+ class << self
11
+ include FRuby::Definer
12
+ defun(:fact, Fixnum) { |n| n * fact(n - 1) }
13
+ defun(:fact, 0) { 1 }
14
+ defun(:fact, 1) { 1 }
15
+ end
16
+ end
17
+
18
+ Math::fact(5) #=> 120
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/rdoctask'
6
+ require 'lib/version'
7
+
8
+ GEM_NAME = 'fruby'
9
+
10
+ spec = Gem::Specification.new do |s|
11
+ s.name = GEM_NAME
12
+ s.version = FRuby::VERSION
13
+ s.has_rdoc = true
14
+ s.extra_rdoc_files = ['README.rdoc', 'LICENSE']
15
+ s.summary = 'Some functional programming features for ruby'
16
+ s.description = s.summary
17
+ s.author = 'Mikhail Shakhanov'
18
+ s.email = 'mshakhan@gmail.com'
19
+ s.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{lib,spec}/**/*")
20
+ s.require_path = "lib"
21
+
22
+ s.add_dependency 'rake'
23
+ s.add_dependency 'rspec'
24
+
25
+ s.required_ruby_version = ">= 1.8.4"
26
+ end
27
+
28
+ Rake::GemPackageTask.new(spec) do |p|
29
+ p.gem_spec = spec
30
+ p.need_tar = true
31
+ p.need_zip = true
32
+ end
33
+
34
+ Rake::RDocTask.new do |rdoc|
35
+ files =['README.rdoc', 'LICENSE', 'lib/**/*.rb']
36
+ rdoc.rdoc_files.add(files)
37
+ rdoc.main = "README.rdoc"
38
+ rdoc.title = "FRuby Docs"
39
+ rdoc.rdoc_dir = 'doc/rdoc'
40
+ rdoc.options << '--line-numbers'
41
+ end
42
+
43
+ desc 'Run specs'
44
+ task :spec do
45
+ spec_path = ENV['SPEC_PATH'] || 'spec'
46
+ system("spec #{spec_path} -c")
47
+ end
48
+
49
+ desc "Generate *.gemspec file"
50
+ task :gemspec do
51
+ path = File.join(File.dirname(__FILE__), "#{GEM_NAME}.gemspec")
52
+ puts %{Writing "#{path}"}
53
+ File.open(path, "w") { |file| file.write(spec.to_ruby) }
54
+ end
@@ -0,0 +1,80 @@
1
+ module FRuby
2
+ # This module implements "pattern matching" function definition style
3
+ #
4
+ # Author:: Mikhail Shakhanov (mailto:mshakhan@gmail.com)
5
+ # Copyright:: Copyright (c) 2009 mshakhan
6
+ # License:: WTFPL
7
+ module Definer
8
+ def self.included(base)
9
+ super
10
+ base.class_eval do
11
+ extend ClassMethods
12
+ end
13
+ end
14
+
15
+ module ClassMethods
16
+ # Defines method in "pattern-matching" style
17
+ #
18
+ # ==== Examples
19
+ #
20
+ # class Test
21
+ # include FRuby::Definer
22
+ # defun(:my_method) { 'empty args' }
23
+ # defun(:my_method, Fixnum) { |n| n }
24
+ # defun(:my_method, 0) { 'zero' }
25
+ # end
26
+ #
27
+ # c = C.new
28
+ # c.my_method # => 'empty args'
29
+ # c.my_method(42) # => 42
30
+ # c.my_method(0) # => 'zero'
31
+ #
32
+ # ==== Parameters
33
+ #
34
+ # * <tt>name</tt> - Method name. Should be a Symbol or a String
35
+ # * <tt>formal_args</tt> - Method's formal parameters. Might be a classes or a values
36
+ # * <tt>&block</tt> - Method definition
37
+ def defun(name, *formal_args, &block)
38
+ define_or_append_condition(name, lambda { |*args|
39
+ FRuby::Matcher::match(formal_args, args)
40
+ }, &block)
41
+ end
42
+
43
+ private
44
+ def append_condition(method_name, condition, &block)
45
+ condition_method_name = define_condition_method(method_name, &block)
46
+ old_method_name = Utils::rand_condition_method_name(method_name)
47
+ alias_method old_method_name, method_name
48
+ private old_method_name
49
+
50
+ define_method method_name do |*args|
51
+ if condition.call(*args)
52
+ method(condition_method_name).call(*args)
53
+ else
54
+ method(old_method_name).call(*args)
55
+ end
56
+ end
57
+ end
58
+
59
+ def define_or_append_condition(method_name, condition, &block)
60
+ unless Utils::has_instance_method?(self, method_name)
61
+ condition_method_name = define_condition_method(method_name, &block)
62
+ define_method method_name do |*args|
63
+ if condition.call(*args)
64
+ method(condition_method_name).call(*args)
65
+ end
66
+ end
67
+ else
68
+ append_condition(method_name, condition, &block)
69
+ end
70
+ end
71
+
72
+ def define_condition_method(method_name, &block)
73
+ condition_method_name = Utils::rand_condition_method_name(method_name)
74
+ define_method(condition_method_name, &block)
75
+ private condition_method_name.to_sym
76
+ condition_method_name
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,49 @@
1
+ class Object
2
+ def blank?
3
+ respond_to?(:empty?) ? empty? : !self
4
+ end
5
+
6
+ def present?
7
+ !blank?
8
+ end
9
+ end
10
+
11
+ class NilClass
12
+ def blank?
13
+ true
14
+ end
15
+ end
16
+
17
+ class FalseClass
18
+ def blank?
19
+ true
20
+ end
21
+ end
22
+
23
+ class TrueClass
24
+ def blank?
25
+ false
26
+ end
27
+ end
28
+
29
+ class Array
30
+ def blank?
31
+ self.compact.empty?
32
+ end
33
+ end
34
+
35
+ class Hash
36
+ alias_method :blank?, :empty?
37
+ end
38
+
39
+ class String
40
+ def blank?
41
+ self.strip.size == 0
42
+ end
43
+ end
44
+
45
+ class Numeric
46
+ def blank?
47
+ false
48
+ end
49
+ end
@@ -0,0 +1,7 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+
3
+ require 'version'
4
+ require 'ext'
5
+ require 'utils'
6
+ require 'matcher'
7
+ require 'definer'
@@ -0,0 +1,41 @@
1
+ module FRuby
2
+ module Matcher extend self
3
+ def match(p1, p2)
4
+ match_by_value(p1, p2) or match_by_class(p1, p2)
5
+ end
6
+
7
+ def match_by_value(p1, p2)
8
+ if p1.is_a?(Array) and p2.is_a?(Array)
9
+ match_arrays_by_value(p1, p2)
10
+ else
11
+ p1 == p2 || (p1.blank? && p2.blank?)
12
+ end
13
+ end
14
+
15
+ def match_by_class(cls, p)
16
+ if cls.is_a?(Array) and p.is_a?(Array)
17
+ match_arrays_by_class(cls, p)
18
+ else
19
+ p.present? and cls == p.class
20
+ end
21
+ end
22
+
23
+ def match_arrays_by_value(p1, p2)
24
+ # TODO Think about it. Does [], [nil] and nil are equals to empty args?
25
+ p1 = p1.flatten.compact
26
+ p2 = p2.flatten.compact
27
+ return false if p1.size != p2.size
28
+ return true if p1.blank? and p2.blank?
29
+ Utils::multiple_all?(p1, p2) do |a1, a2|
30
+ match_by_value(a1, a2)
31
+ end
32
+ end
33
+
34
+ def match_arrays_by_class(cls, p)
35
+ return false if cls.size != p.size
36
+ Utils::multiple_all?(cls, p) do |a1, a2|
37
+ match_by_class(a1, a2)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,25 @@
1
+ module FRuby
2
+ module Utils extend self
3
+ def rand_condition_method_name(prefix, size = 8)
4
+ alphabet = ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a
5
+ "__#{prefix}_condition_#{Array.new(size) { alphabet[rand(alphabet.size)] }.join}__"
6
+ end
7
+
8
+ def has_instance_method?(obj, method_name)
9
+ obj.instance_methods.include? method_name.to_s
10
+ end
11
+
12
+ def multiple_each(*args, &block)
13
+ args.first.size.times do |index|
14
+ block.call(args.map { |arg| arg[index] })
15
+ end
16
+ end
17
+
18
+ def multiple_all?(*args, &block)
19
+ multiple_each(*args) do |*each_args|
20
+ return false unless block.call(*each_args)
21
+ end
22
+ true
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module FRuby
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,35 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'fruby')
2
+
3
+ class DefinerTest
4
+ include FRuby::Definer
5
+
6
+ defun(:test) { :empty } # empty args (no args, nil, [], [nil])
7
+ defun(:test, String) { |s| s }
8
+ defun(:test, 0) { :zero }
9
+ end
10
+
11
+
12
+ describe FRuby::Definer do
13
+ before :each do
14
+ @inst = DefinerTest.new
15
+ end
16
+
17
+ it "Should return :empty if empty args" do
18
+ @inst.test.should == :empty
19
+ @inst.test(nil).should == :empty
20
+ @inst.test([]).should == :empty
21
+ end
22
+
23
+ it "Should return passed string if string passed" do
24
+ @inst.test('string').should == 'string'
25
+ end
26
+
27
+ it "Should return :zero string if 0 passed" do
28
+ @inst.test(0).should == :zero
29
+ end
30
+
31
+ it "Condition methods should be private" do
32
+ DefinerTest.public_instance_methods.grep(/^test/).size.should == 1
33
+ end
34
+ end
35
+
@@ -0,0 +1,24 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'fruby')
2
+
3
+ describe FRuby::Matcher do
4
+ it "Should match equal objects" do
5
+ FRuby::Matcher::match(0, 0).should == true
6
+ FRuby::Matcher::match([0, 1, 2], [0, 1, 2]).should == true
7
+ end
8
+
9
+ it "Should match by class" do
10
+ FRuby::Matcher::match(Fixnum, 0).should == true
11
+ FRuby::Matcher::match([Fixnum, String], [0, 'a']).should == true
12
+ end
13
+
14
+ it "Should match empty objects" do # but what is empty object?
15
+ FRuby::Matcher::match([], [nil]).should == true
16
+ FRuby::Matcher::match(nil, []).should == true
17
+ FRuby::Matcher::match(nil, '').should == true
18
+ end
19
+
20
+ it "Should not match not equal objects" do
21
+ FRuby::Matcher::match(0, 1).should_not == true
22
+ end
23
+ end
24
+
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'fruby')
2
+
3
+ class UtilsTest
4
+ def method_exists; end
5
+ end
6
+
7
+ describe FRuby::Utils do
8
+ it "Should return true if class has an instance method by string and symbol" do
9
+ FRuby::Utils::has_instance_method?(UtilsTest, 'method_exists').should == true
10
+ FRuby::Utils::has_instance_method?(UtilsTest, :method_exists).should == true
11
+ end
12
+
13
+ it "Should return false if class has not an instance method by string and symbol" do
14
+ FRuby::Utils::has_instance_method?(UtilsTest, 'method_doesnt_exists').should_not == true
15
+ FRuby::Utils::has_instance_method?(UtilsTest, :method_doesnt_exists).should_not == true
16
+ end
17
+ end
18
+
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mshakhan-fruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - mshakhan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-21 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rake
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description: Some functional programming features for ruby
36
+ email: mshakhan@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README.rdoc
43
+ - LICENSE
44
+ files:
45
+ - LICENSE
46
+ - README.rdoc
47
+ - Rakefile
48
+ - lib/definer.rb
49
+ - lib/version.rb
50
+ - lib/fruby.rb
51
+ - lib/utils.rb
52
+ - lib/matcher.rb
53
+ - lib/ext.rb
54
+ - spec/matcher_spec.rb
55
+ - spec/definer_spec.rb
56
+ - spec/utils_spec.rb
57
+ has_rdoc: true
58
+ homepage:
59
+ licenses:
60
+ post_install_message:
61
+ rdoc_options: []
62
+
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 1.8.4
70
+ version:
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: "0"
76
+ version:
77
+ requirements: []
78
+
79
+ rubyforge_project:
80
+ rubygems_version: 1.3.5
81
+ signing_key:
82
+ specification_version: 2
83
+ summary: Some functional programming features for ruby
84
+ test_files: []
85
+