mshakhan-fruby 0.0.1

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.
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
+