traits 0.9.0 → 0.9.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.
@@ -0,0 +1,136 @@
1
+ URLS
2
+
3
+ http://rubyforge.org/projects/codeforpeople/
4
+ http://codeforpeople.com/lib/ruby/traits
5
+
6
+ ABOUT
7
+
8
+ traits.rb is set of attr_* like methods on steroids, caffeine, and botox. it
9
+ encourages better living through meta-programming and uniform access
10
+ priciples. traits.rb supports smart inheritence of class attributes and a
11
+ fistful of hooks for veryifying and munging attr values.
12
+
13
+ VERSION
14
+
15
+ 0.9.1
16
+
17
+ HISTORY
18
+
19
+ 0.9.0
20
+ - luke kaines made quite a few suggestions and bug reports that enabled this
21
+ release including making a few methods indifferent about string/symbol
22
+ args/keys and the introduction of a simple method 'trait_init' that can be
23
+ used to create keyword based initializers, eg:
24
+
25
+ require 'traits'
26
+
27
+ class C
28
+ include TraitInit
29
+
30
+ trait :a, :type => Integer
31
+ trait :b, :type => Integer
32
+
33
+ def initialize opts = {}
34
+ trait_init opts
35
+ end
36
+ end
37
+
38
+ C::new :a => 4, :b => 2
39
+
40
+ 0.8.0
41
+ - traits now supports a whole slew of hooks that can be registered to fire
42
+ pre or post setting an attribute, to cast a value to another type, to
43
+ munge a value destructively, to require only certain types, to require a
44
+ certain ducktype signature, and to validate arguments passed. check out
45
+ sample/m.rb, sample/n.rb, or sample.o.rb to see it in action. the
46
+ mechanism is quite flexible allowing method names, lambdas of varying
47
+ arity, and lists of either/or to be passed to any hook.
48
+
49
+ - you can find a gem for trais on codeforpeople - but i've still not coded
50
+ up automated updating from codeforpeople to rubyforge so it won't show up
51
+ as a remote gem yet.
52
+
53
+ 0.7.0
54
+ - patched in the support i had written eariler for 'hooks' to be called
55
+ pre/post setting a trait. plus shortcut to 'validate' traits which simply
56
+ sets up a 'pre' hook which is used as a predicate. eg:
57
+
58
+ class C; trait 'number', 'validate' => proc{|n| Numeric === n}
59
+
60
+ pre and post hooks are used in the same way, eg:
61
+
62
+ class C
63
+ trait 'a',
64
+ 'pre' => proc{|val| p "#{ val } to set with"},
65
+ 'post' => proc{|val| p "#{ val } set"},
66
+ end
67
+
68
+ but the really cool thing is that all of these blocks are both passed the
69
+ value in question but also evaluate with 'self' set appropriately. eg
70
+
71
+ class Car
72
+ positive_int = lambda{|n| Fixnum === n and n > 0}
73
+ legal = proc{|s| s < speed_limit}
74
+
75
+ trait 'speed_limit', 'validate' => positive_int, 'default' => 42
76
+ trait 'speed', 'validate' => legal
77
+ end
78
+
79
+ c = Car::new
80
+ c.speed = 115
81
+
82
+ works as you'd expect:
83
+
84
+ (eval):14:in `speed=': validation of speed=(115) failed! (ArgumentError)
85
+ from a.rb:13
86
+
87
+ 0.6.0
88
+ - fixed bug in where a default trait given as an empty array, eg:
89
+
90
+ class C; has 'a' => []; end
91
+
92
+ was exploded into the empty list when passed to the setter to initialize
93
+ the default value.
94
+
95
+ 0.5.0
96
+ - general code cleanup
97
+
98
+ 0.4.0
99
+ - tweaked writer code so multiple values can be passed to setters
100
+ - tweaked method of running blocks to use instance_eval so explicit 'this'
101
+ arg is no longer needed (though it can still be used)
102
+
103
+ 0.3.0
104
+ added ability of default values to be specified with block for deferred
105
+ context sensitive initialization (see sample/c.rb)
106
+
107
+ 0.1.0
108
+
109
+ completely reworked impl so NO parsing of inspect strings is required -
110
+ it's all straight methods (albeit quite confusing ones) now. the
111
+ interface is unchanged.
112
+
113
+ 0.0.0
114
+
115
+ initial version
116
+
117
+
118
+ AUTHOR
119
+
120
+ ara [dot] t [dot] howard [at] noaa [dot] gov
121
+
122
+ SAMPLES
123
+
124
+ @samples
125
+
126
+ CAVEATS
127
+
128
+ this library is experimental and subject to change - though it has not for
129
+ several versions and much of my code hinges is on it now so you can expect the
130
+ interface to be stable in the near future - the only changes planned are those
131
+ that fix bugs or add features.
132
+
133
+ LICENSE
134
+
135
+ same as ruby's
136
+
@@ -0,0 +1,23 @@
1
+ lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
2
+
3
+ require 'rubygems'
4
+
5
+ Gem::Specification::new do |spec|
6
+ spec.name = lib
7
+ spec.version = version
8
+ spec.platform = Gem::Platform::RUBY
9
+ spec.summary = lib
10
+
11
+ spec.files = Dir::glob "**/**"
12
+ spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
13
+
14
+ spec.require_path = "lib"
15
+ spec.autorequire = lib
16
+
17
+ spec.has_rdoc = File::exist? "doc"
18
+ spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
19
+
20
+ spec.author = "Ara T. Howard"
21
+ spec.email = "ara.t.howard@noaa.gov"
22
+ spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/"
23
+ end
@@ -0,0 +1,29 @@
1
+ $VERBOSE=nil
2
+ def indent s, n = 2
3
+ ws = ' ' * n
4
+ s.gsub %r/^/, ws
5
+ end
6
+
7
+ template = IO::read 'README.tmpl'
8
+
9
+ samples = ''
10
+ prompt = '~ > '
11
+
12
+ Dir['sample/*'].each do |sample|
13
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
14
+
15
+ cmd = "cat #{ sample }"
16
+ samples << indent(prompt + cmd, 2) << "\n\n"
17
+ samples << indent(`#{ cmd }`, 4) << "\n"
18
+
19
+ cmd = "ruby #{ sample }"
20
+ samples << indent(prompt + cmd, 2) << "\n\n"
21
+
22
+ cmd = "ruby -I ./lib -r ./lib/traits.rb #{ sample }"
23
+ samples << indent(`#{ cmd } 2>&1`, 4) << "\n"
24
+ end
25
+
26
+ #samples.gsub! %r/^/, ' '
27
+
28
+ readme = template.gsub %r/^\s*@samples\s*$/, samples
29
+ print readme
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rbconfig'
3
+ require 'find'
4
+ require 'ftools'
5
+ require 'tempfile'
6
+ include Config
7
+
8
+ LIBDIR = "lib"
9
+ LIBDIR_MODE = 0644
10
+
11
+ BINDIR = "bin"
12
+ BINDIR_MODE = 0755
13
+
14
+
15
+ $srcdir = CONFIG["srcdir"]
16
+ $version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
17
+ $libdir = File.join(CONFIG["libdir"], "ruby", $version)
18
+ $archdir = File.join($libdir, CONFIG["arch"])
19
+ $site_libdir = $:.find {|x| x =~ /site_ruby$/}
20
+ $bindir = CONFIG["bindir"] || CONFIG['BINDIR']
21
+ $ruby_install_name = CONFIG['ruby_install_name'] || CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
22
+ $ruby_ext = CONFIG['EXEEXT'] || ''
23
+ $ruby = File.join($bindir, ($ruby_install_name + $ruby_ext))
24
+
25
+ if !$site_libdir
26
+ $site_libdir = File.join($libdir, "site_ruby")
27
+ elsif $site_libdir !~ %r/#{Regexp.quote($version)}/
28
+ $site_libdir = File.join($site_libdir, $version)
29
+ end
30
+
31
+ def install_rb(srcdir=nil, destdir=nil, mode=nil, bin=nil)
32
+ #{{{
33
+ path = []
34
+ dir = []
35
+ Find.find(srcdir) do |f|
36
+ next unless FileTest.file?(f)
37
+ next if (f = f[srcdir.length+1..-1]) == nil
38
+ next if (/CVS$/ =~ File.dirname(f))
39
+ next if f =~ %r/\.lnk/
40
+ path.push f
41
+ dir |= [File.dirname(f)]
42
+ end
43
+ for f in dir
44
+ next if f == "."
45
+ next if f == "CVS"
46
+ File::makedirs(File.join(destdir, f))
47
+ end
48
+ for f in path
49
+ next if (/\~$/ =~ f)
50
+ next if (/^\./ =~ File.basename(f))
51
+ unless bin
52
+ File::install(File.join(srcdir, f), File.join(destdir, f), mode, true)
53
+ else
54
+ from = File.join(srcdir, f)
55
+ to = File.join(destdir, f)
56
+ shebangify(from) do |sf|
57
+ $deferr.print from, " -> ", File::catname(from, to), "\n"
58
+ $deferr.printf "chmod %04o %s\n", mode, to
59
+ File::install(sf, to, mode, false)
60
+ end
61
+ end
62
+ end
63
+ #}}}
64
+ end
65
+ def shebangify f
66
+ #{{{
67
+ open(f) do |fd|
68
+ buf = fd.read 42
69
+ if buf =~ %r/^\s*#\s*!.*ruby/o
70
+ ftmp = Tempfile::new("#{ $$ }_#{ File::basename(f) }")
71
+ begin
72
+ fd.rewind
73
+ ftmp.puts "#!#{ $ruby }"
74
+ while((buf = fd.read(8192)))
75
+ ftmp.write buf
76
+ end
77
+ ftmp.close
78
+ yield ftmp.path
79
+ ensure
80
+ ftmp.close!
81
+ end
82
+ else
83
+ yield f
84
+ end
85
+ end
86
+ #}}}
87
+ end
88
+ def ARGV.switch
89
+ #{{{
90
+ return nil if self.empty?
91
+ arg = self.shift
92
+ return nil if arg == '--'
93
+ if arg =~ /^-(.)(.*)/
94
+ return arg if $1 == '-'
95
+ raise 'unknown switch "-"' if $2.index('-')
96
+ self.unshift "-#{$2}" if $2.size > 0
97
+ "-#{$1}"
98
+ else
99
+ self.unshift arg
100
+ nil
101
+ end
102
+ #}}}
103
+ end
104
+ def ARGV.req_arg
105
+ #{{{
106
+ self.shift || raise('missing argument')
107
+ #}}}
108
+ end
109
+ def linkify d, linked = []
110
+ #--{{{
111
+ if test ?d, d
112
+ versioned = Dir[ File::join(d, "*-[0-9].[0-9].[0-9].rb") ]
113
+ versioned.each do |v|
114
+ src, dst = v, v.gsub(%r/\-[\d\.]+\.rb$/, '.rb')
115
+ lnk = nil
116
+ begin
117
+ if test ?l, dst
118
+ lnk = "#{ dst }.lnk"
119
+ puts "#{ dst } -> #{ lnk }"
120
+ File::rename dst, lnk
121
+ end
122
+ unless test ?e, dst
123
+ puts "#{ src } -> #{ dst }"
124
+ File::copy src, dst
125
+ linked << dst
126
+ end
127
+ ensure
128
+ if lnk
129
+ at_exit do
130
+ puts "#{ lnk } -> #{ dst }"
131
+ File::rename lnk, dst
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ linked
138
+ #--}}}
139
+ end
140
+
141
+
142
+ #
143
+ # main program
144
+ #
145
+
146
+ libdir = $site_libdir
147
+ bindir = $bindir
148
+ no_linkify = false
149
+ linked = nil
150
+ help = false
151
+
152
+ usage = <<-usage
153
+ #{ File::basename $0 }
154
+ -d, --destdir <destdir>
155
+ -l, --libdir <libdir>
156
+ -b, --bindir <bindir>
157
+ -r, --ruby <ruby>
158
+ -n, --no_linkify
159
+ -h, --help
160
+ usage
161
+
162
+ begin
163
+ while switch = ARGV.switch
164
+ case switch
165
+ when '-d', '--destdir'
166
+ libdir = ARGV.req_arg
167
+ when '-l', '--libdir'
168
+ libdir = ARGV.req_arg
169
+ when '-b', '--bindir'
170
+ bindir = ARGV.req_arg
171
+ when '-r', '--ruby'
172
+ $ruby = ARGV.req_arg
173
+ when '-n', '--no_linkify'
174
+ no_linkify = true
175
+ when '-h', '--help'
176
+ help = true
177
+ else
178
+ raise "unknown switch #{switch.dump}"
179
+ end
180
+ end
181
+ rescue
182
+ STDERR.puts $!.to_s
183
+ STDERR.puts usage
184
+ exit 1
185
+ end
186
+
187
+ if help
188
+ STDOUT.puts usage
189
+ exit
190
+ end
191
+
192
+ unless no_linkify
193
+ linked = linkify('lib') + linkify('bin')
194
+ end
195
+
196
+ install_rb(LIBDIR, libdir, LIBDIR_MODE)
197
+ install_rb(BINDIR, bindir, BINDIR_MODE, bin=true)
198
+
199
+ if linked
200
+ linked.each{|path| File::rm_f path}
201
+ end
@@ -1,5 +1,5 @@
1
1
  $__TRAIT_DEBUG__ = ENV['__TRAIT_DEBUG__'] || ENV['TRAIT_DEBUG'] || ENV['DEBUG']
2
- $__TRAIT_VERSION__ = "0.9.0"
2
+ $__TRAIT_VERSION__ = "0.9.1"
3
3
 
4
4
  class Object
5
5
  #--{{{
@@ -670,18 +670,44 @@ end
670
670
 
671
671
  module TraitInit
672
672
  #--{{{
673
- def trait_init opts = {}
674
- #--{{{
675
- opts.each do |k,v|
676
- k = "#{ k }"
677
- if respond_to? k
678
- send k, v
679
- else
680
- raise ArgumentError, "invalid trait -- #{ self.class }##{ k }"
673
+ module InstaceMethods
674
+ def trait_init *argv
675
+ #--{{{
676
+ args, opts = argv.partition{|arg| not Hash === arg}
677
+ args.flatten!
678
+ opts = opts.inject({}){|h,h2| h.update h2}
679
+ msgs = r_traits
680
+ args.each{|arg| send msgs.shift, v}
681
+ opts.each do |k,v|
682
+ k = "#{ k }"
683
+ if respond_to? k
684
+ send k, v
685
+ else
686
+ raise ArgumentError, "invalid trait -- #{ self.class }##{ k }"
687
+ end
681
688
  end
689
+ #--}}}
682
690
  end
691
+ alias_method "traitinit", "trait_init"
692
+ end
693
+ module ClassMethods
694
+ def trait_initialize *a, &b
695
+ traits *a unless a.empty?
696
+ module_eval{
697
+ def initialize(*a, &b)
698
+ super() if defined? super
699
+ trait_init *a
700
+ end
701
+ }
702
+ end
703
+ alias_method "traitinitialize", "trait_initialize"
704
+ end
705
+ def self.included other
706
+ #--{{{
707
+ other.extend ClassMethods
708
+ other.module_eval{ include InstaceMethods }
709
+ super
683
710
  #--}}}
684
711
  end
685
- alias_method "traitinit", "trait_init"
686
712
  #--}}}
687
713
  end