magnetic 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,31 @@
1
+
2
+ lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
3
+
4
+ require 'rubygems'
5
+
6
+ Gem::Specification::new do |spec|
7
+ $VERBOSE = nil
8
+ spec.name = lib
9
+ spec.version = version
10
+ spec.platform = Gem::Platform::RUBY
11
+ spec.summary = lib
12
+
13
+ spec.files = Dir::glob "**/**"
14
+ spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
15
+
16
+ spec.require_path = "lib"
17
+ spec.autorequire = lib
18
+
19
+ spec.has_rdoc = File::exist? "doc"
20
+ spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
21
+ spec.add_dependency 'pervasives', '~> 1.0'
22
+ spec.add_dependency 'arrayfields', '~> 3.7'
23
+ spec.add_dependency 'attributes', '~> 3.3'
24
+ spec.add_dependency 'prototype', '~> 2.0'
25
+
26
+ spec.extensions << "extconf.rb" if File::exists? "extconf.rb"
27
+
28
+ spec.author = "Ara T. Howard"
29
+ spec.email = "ara.t.howard@gmail.com"
30
+ spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/"
31
+ end
@@ -0,0 +1,21 @@
1
+ #
2
+ # built-in
3
+ #
4
+ require 'pathname'
5
+ require 'fileutils'
6
+ #
7
+ # gems
8
+ #
9
+ require 'rubygems'
10
+ require 'pervasives'
11
+ require 'arrayfields'
12
+ require 'attributes'
13
+ require 'prototype'
14
+ #
15
+ # magnetic
16
+ #
17
+ require 'magnetic/binding_of_caller'
18
+ require 'magnetic/rubyext'
19
+ require 'magnetic/field'
20
+ require 'magnetic/interface'
21
+ require 'magnetic/rails'
@@ -0,0 +1,84 @@
1
+ begin
2
+ require 'simplecc'
3
+ rescue LoadError
4
+ class Continuation # :nodoc: # for RDoc
5
+ end
6
+ def Continuation.create(*args, &block) # :nodoc:
7
+ cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
8
+ result ||= args
9
+ return *[cc, *result]
10
+ end
11
+ end
12
+
13
+ class Binding; end # for RDoc
14
+ # This method returns the binding of the method that called your
15
+ # method. It will raise an Exception when you're not inside a method.
16
+ #
17
+ # It's used like this:
18
+ # def inc_counter(amount = 1)
19
+ # Binding.of_caller do |binding|
20
+ # # Create a lambda that will increase the variable 'counter'
21
+ # # in the caller of this method when called.
22
+ # inc = eval("lambda { |arg| counter += arg }", binding)
23
+ # # We can refer to amount from inside this block safely.
24
+ # inc.call(amount)
25
+ # end
26
+ # # No other statements can go here. Put them inside the block.
27
+ # end
28
+ # counter = 0
29
+ # 2.times { inc_counter }
30
+ # counter # => 2
31
+ #
32
+ # Binding.of_caller must be the last statement in the method.
33
+ # This means that you will have to put everything you want to
34
+ # do after the call to Binding.of_caller into the block of it.
35
+ # This should be no problem however, because Ruby has closures.
36
+ # If you don't do this an Exception will be raised. Because of
37
+ # the way that Binding.of_caller is implemented it has to be
38
+ # done this way.
39
+ def Binding.of_caller(&block)
40
+ old_critical = Thread.critical
41
+ Thread.critical = true
42
+ count = 0
43
+ cc, result, error, extra_data = Continuation.create(nil, nil)
44
+ error.call if error
45
+
46
+ tracer = lambda do |*args|
47
+ type, context, extra_data = args[0], args[4], args
48
+ if type == "return"
49
+ count += 1
50
+ # First this method and then calling one will return --
51
+ # the trace event of the second event gets the context
52
+ # of the method which called the method that called this
53
+ # method.
54
+ if count == 2
55
+ # It would be nice if we could restore the trace_func
56
+ # that was set before we swapped in our own one, but
57
+ # this is impossible without overloading set_trace_func
58
+ # in current Ruby.
59
+ set_trace_func(nil)
60
+ cc.call(eval("binding", context), nil, extra_data)
61
+ end
62
+ elsif type == "line" then
63
+ nil
64
+ elsif type == "c-return" and extra_data[3] == :set_trace_func then
65
+ nil
66
+ else
67
+ set_trace_func(nil)
68
+ error_msg = "Binding.of_caller used in non-method context or " +
69
+ "trailing statements of method using it aren't in the block."
70
+ cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
71
+ end
72
+ end
73
+
74
+ unless result
75
+ set_trace_func(tracer)
76
+ return nil
77
+ else
78
+ Thread.critical = old_critical
79
+ case block.arity
80
+ when 1 then yield(result)
81
+ else yield(result, extra_data)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,227 @@
1
+ module Magnetic
2
+ module Field
3
+ Base = Object.prototype do
4
+ name nil
5
+ owner nil
6
+ #controller nil
7
+ model nil
8
+ #interface nil
9
+ #records nil
10
+ value nil
11
+ #path nil
12
+ type :html
13
+
14
+ def __
15
+ @__ ||= Pervasives::Proxy.new(self)
16
+ end
17
+
18
+ def to_s
19
+ value.to_s
20
+ end
21
+
22
+ attribute('template_root'){ File.join RAILS_ROOT, 'app', 'views', 'magnetic' }
23
+ attribute('template_dir'){ File.join template_root, File.join(*owner.name.gsub(%r/^:+/,'').split(%r/::/)).downcase }
24
+ attribute('template_base'){ name }
25
+ #attribute('template_ext'){ type.to_s }
26
+ attribute('template_prefix'){ File.join(template_dir, template_base) }
27
+ attribute('template_inline'){ send "template_inline_#{ type }" }
28
+ attribute('template_text'){ nil }
29
+ attribute('template_map'){ { 'html' => 'rhtml', 'xml' => 'rxml' } }
30
+
31
+ #
32
+ # TODO - this needs to be thought out further
33
+ #
34
+ def render *argv
35
+ raise 'recursive render!' if defined?(@inside_render) and @inside_render
36
+ @inside_render = true
37
+ begin
38
+ field = self
39
+
40
+ type = argv.delete_first{|arg| String === arg or Symbol === arg } || self.type
41
+ type = type.to_s
42
+
43
+ options = argv.delete_first{|arg| Hash === arg} || {}
44
+ options.to_options!
45
+
46
+ msg = options.delete(:render) || :render_to_string
47
+
48
+ text = options[:text] || template_text rescue nil
49
+ inline = options[:inline] || template_inline rescue nil
50
+
51
+ unless text or inline
52
+ file = options[:file]
53
+ unless file
54
+ ext = (template_map[type] || type).gsub %r/^\.?/, '.'
55
+ options[:file] = template_prefix + ext
56
+ end
57
+ end
58
+
59
+ controller.clone.instance_eval do
60
+ @field = field
61
+ (options[:locals] ||= {}).update :field => @field
62
+ send msg, options
63
+ end
64
+ ensure
65
+ @inside_render = false
66
+ end
67
+ end
68
+
69
+ def configure options = {}, &block
70
+ options.to_options!
71
+ prototyping do
72
+ options.each do |k,v|
73
+ begin
74
+ __send__ "#{ k }=", v
75
+ rescue
76
+ __attribute__ k => v
77
+ end
78
+ end
79
+ end
80
+ prototyping &block
81
+ self
82
+ end
83
+ alias_method 'configured', 'configure'
84
+
85
+ def to_proc
86
+ @to_proc ||= lambda do |options|
87
+ options.to_options!
88
+ field = self
89
+ value = options[:value]
90
+ unless value.nil?
91
+ sc =
92
+ class << value
93
+ self
94
+ end
95
+ sc.module_eval do
96
+ define_method :field do
97
+ field.configure options
98
+ field
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+
106
+ def to_proc
107
+ @to_proc ||= lambda do |options|
108
+ field = self
109
+ field_options = options.to_options
110
+ value = options[:value]
111
+ raise ArgumentError, "no value in <#{ options.inspect }>" unless value
112
+ value.extend ConfiguredFieldMethod
113
+ value.field = field
114
+ value.field_options = field_options
115
+ end
116
+ end
117
+
118
+ module ConfiguredFieldMethod
119
+ attr_writer 'field'
120
+ attr_writer 'field_options'
121
+
122
+ def field
123
+ @field_options.each do |k, v|
124
+ unless @field.respond_to? k
125
+ sc =
126
+ class << @field
127
+ self
128
+ end
129
+ sc.module_eval{ attribute k }
130
+ end
131
+ @field.send "#{ k }=", v
132
+ end
133
+ @field
134
+ end
135
+ end
136
+
137
+ def === other
138
+ Base.class === other
139
+ end
140
+ end
141
+
142
+ ### TODO try not to use array fields here
143
+ class Set < ::Array
144
+ include Fieldable
145
+ class << self
146
+ def [] *a, &b
147
+ a = super
148
+ ensure
149
+ a.fields = []
150
+ end
151
+ end
152
+ def initialize *a, &b
153
+ super
154
+ ensure
155
+ self.fields = []
156
+ end
157
+ end
158
+
159
+ module DSL
160
+ def fieldset
161
+ @fieldset ||= Field::Set[]
162
+ end
163
+ def field *argv, &block
164
+ name = argv.delete_first{|arg| String === arg or Symbol === arg }
165
+ base = argv.delete_first{|arg| Field::Base.class === arg}
166
+ configuring = argv.delete_first{|arg| ['configure', :configure, 'configuring', :configuring].include? arg}
167
+ options = argv.delete_first{|arg| Hash === arg}
168
+
169
+ name ||= base.name
170
+ raise ArgumentError, 'nameless field!' unless name
171
+ name = name.to_s
172
+
173
+ if options.nil? and base.nil? and block.nil?
174
+ field = field_for name
175
+ field.clone unless field.nil?
176
+ else
177
+ options ||= {}
178
+ options.to_options!
179
+ field =
180
+ if configuring
181
+ field_for name
182
+ else
183
+ base ||= Field::Base
184
+ field = base.clone
185
+ field.name = name
186
+ field.owner = self
187
+ field
188
+ end
189
+
190
+ field.configure options, &block
191
+
192
+ #p [ (field.owner.name rescue field.owner.class.name), field.name, (configuring ? :configuring : false), caller.first ]
193
+
194
+ unless configuring
195
+ raise ArgumentError, "duplicate field '#{ name }' in #{ fieldset[name].inspect }" if fieldset.has_key?(field.name)
196
+ fieldset[field.name] = field
197
+ end
198
+
199
+ field
200
+ end
201
+ end
202
+ def field_for name
203
+ fieldset[name.to_s]
204
+ end
205
+ def self.included other
206
+ super
207
+ ensure
208
+ other.extend self
209
+ end
210
+ end
211
+ end
212
+
213
+ def self.field *argv, &block
214
+ name = argv.delete_first{|arg| String === arg or Symbol === arg }
215
+ base = argv.delete_first{|arg| Field::Base.class === arg}
216
+ configure = argv.delete_first{|arg| ['configure', :configure].include? arg}
217
+ options = argv.delete_first{|arg| Hash === arg}
218
+ options ||= {}
219
+ options.to_options!
220
+ base ||= Field::Base
221
+ field = base.clone
222
+ field.name = name
223
+ field.owner = self
224
+ field.configure options, &block
225
+ field
226
+ end
227
+ end
@@ -0,0 +1,99 @@
1
+ module Magnetic
2
+ class Path < ::String; end
3
+ def self.path(*a, &b) a.size == 0 ? Path : Path.new(*a, &b) end
4
+
5
+ class Interface
6
+ include Magnetic::Field::DSL
7
+
8
+ attribute 'records'
9
+ attribute 'mapping'
10
+
11
+ def initialize options = {}, &block
12
+ options.to_options!
13
+ records = options[:records]
14
+ controller = options[:controller]
15
+ @records = (( Array === records and ActiveRecord::Base === records[0] )) ? records : [records]
16
+ @records = [] if records.nil?
17
+ @controller = controller
18
+ @mapping = []
19
+ instance_eval &block if block
20
+ post_initialize
21
+ end
22
+
23
+ def map mapping
24
+ mapping.each do |key, value|
25
+ key = key.to_s
26
+ raise ArgumentError, 'empty key!' if key.empty?
27
+ raise ArgumentError, 'no value!' if value.nil?
28
+ @mapping << [key, value]
29
+ if Magnetic::Field::Base === value
30
+ field(value) unless field(value.name)
31
+ end
32
+ end
33
+ end
34
+
35
+ def post_initialize
36
+ map!
37
+ end
38
+
39
+ def map!
40
+ @records.each{|record| map_record :record => record, :mapping => @mapping} unless @mapping.empty?
41
+ end
42
+
43
+ def map_record options = {}
44
+ options.to_options!
45
+
46
+ record = options.delete :record
47
+ mapping = options.delete :mapping
48
+ route = options.delete :route
49
+
50
+ table_name = record.class.table_name
51
+ id = record.id
52
+
53
+ (( route ||= [] )) << "#{ table_name }[#{ id }]"
54
+
55
+ mapping.each do |path, block|
56
+ head, *tail = path.split '.'
57
+ m, head, array, *ignored = %r/^(.*?)(\[\*?\])?$/o.match(head).to_a
58
+
59
+ if array
60
+ subrecords = record.send head
61
+ subrecords = [subrecords] unless subrecords.class == Array
62
+ subpath = tail.join '.'
63
+ subblock = block
64
+ submapping = [[ subpath, subblock ]]
65
+ subrecords.each do |subrecord|
66
+ subroute = route.clone
67
+ map_record :record => subrecord, :mapping => submapping, :route => subroute
68
+ end
69
+ else
70
+ value = record.send head
71
+ path = Magnetic.path(( [route, head].join('.') ))
72
+ block.to_proc.call :path => path,
73
+ :value => value,
74
+ :model => record.class,
75
+ :table_name => table_name,
76
+ :column_name => head,
77
+ :record => record,
78
+ :interface => self,
79
+ :controller => @controller
80
+ end
81
+ end
82
+ end
83
+
84
+ module DSL
85
+ def interface *a, &b
86
+ if a.empty? and b.nil?
87
+ @interface
88
+ else
89
+ @interface = Interface.new :records => a.shift, :controller => self, &b
90
+ end
91
+ end
92
+ def self.included other
93
+ super
94
+ ensure
95
+ other.extend self
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,32 @@
1
+ if defined? Rails or defined? RAILS
2
+ class ActiveRecord::Base
3
+ include Magnetic::Field::DSL
4
+
5
+ def self.field_for name
6
+ name = name.to_s
7
+ fieldset[name] or generate_default_field_for(name)
8
+ end
9
+
10
+ def self.generate_default_field_for name
11
+ cname = name.to_s
12
+ m = self
13
+ raise ArgumentError, "no such column <#{ cname }>" unless columns_hash[cname]
14
+ field cname do
15
+ model m
16
+ end
17
+ end
18
+ end
19
+
20
+ if defined? ActionController
21
+ class ActionController::Base
22
+ include Magnetic::Interface::DSL
23
+ end
24
+ end
25
+
26
+ unless defined? ApplicationController
27
+ class ApplicationController < ActionController::Base; end
28
+ end
29
+ class ApplicationController
30
+ include Magnetic::Interface::DSL
31
+ end
32
+ end
@@ -0,0 +1,30 @@
1
+ class Object
2
+ def higherself
3
+ Binding.of_caller{|binding| eval 'self', binding}
4
+ end
5
+ end
6
+ class Hash
7
+ unless instance_methods.include? 'to_options'
8
+ def to_options
9
+ keys.inject({}){|h,k| h.update k.to_s.to_sym => self[k]}
10
+ end
11
+ end
12
+ unless instance_methods.include? 'to_options!'
13
+ def to_options!
14
+ replace to_options
15
+ end
16
+ end
17
+ end
18
+ class Array
19
+ def delete_first *argv, &block
20
+ match = block ? block : lambda{|arg| argv.first == arg}
21
+ at = nil
22
+ each_with_index do |element, index|
23
+ if match[element]
24
+ at = index
25
+ break
26
+ end
27
+ end
28
+ at ? delete_at(at) : nil
29
+ end
30
+ end
File without changes
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.2
3
+ specification_version: 1
4
+ name: magnetic
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2007-06-04 00:00:00 -06:00
8
+ summary: magnetic
9
+ require_paths:
10
+ - lib
11
+ email: ara.t.howard@gmail.com
12
+ homepage: http://codeforpeople.com/lib/ruby/magnetic/
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: magnetic
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Ara T. Howard
31
+ files:
32
+ - gemspec.rb
33
+ - lib
34
+ - lib/magnetic
35
+ - lib/magnetic/binding_of_caller.rb
36
+ - lib/magnetic/field.rb
37
+ - lib/magnetic/interface.rb
38
+ - lib/magnetic/rails.rb
39
+ - lib/magnetic/rubyext.rb
40
+ - lib/magnetic.rb
41
+ - magnetic-0.0.1.gem
42
+ test_files: []
43
+
44
+ rdoc_options: []
45
+
46
+ extra_rdoc_files: []
47
+
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ requirements: []
53
+
54
+ dependencies:
55
+ - !ruby/object:Gem::Dependency
56
+ name: pervasives
57
+ version_requirement:
58
+ version_requirements: !ruby/object:Gem::Version::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: "1.0"
63
+ version:
64
+ - !ruby/object:Gem::Dependency
65
+ name: arrayfields
66
+ version_requirement:
67
+ version_requirements: !ruby/object:Gem::Version::Requirement
68
+ requirements:
69
+ - - ~>
70
+ - !ruby/object:Gem::Version
71
+ version: "3.7"
72
+ version:
73
+ - !ruby/object:Gem::Dependency
74
+ name: attributes
75
+ version_requirement:
76
+ version_requirements: !ruby/object:Gem::Version::Requirement
77
+ requirements:
78
+ - - ~>
79
+ - !ruby/object:Gem::Version
80
+ version: "3.3"
81
+ version:
82
+ - !ruby/object:Gem::Dependency
83
+ name: prototype
84
+ version_requirement:
85
+ version_requirements: !ruby/object:Gem::Version::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: "2.0"
90
+ version: