dataview 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +58 -0
- data/lib/data_view.rb +158 -0
- data/lib/dataview.rb +1 -0
- data/test/tc_data_view.rb +138 -0
- data/test/ts_data_view.rb +2 -0
- metadata +45 -0
data/README
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
Data View is copyrighted free software by Brian Takita <brian.takita@gmail.com>.
|
2
|
+
You can redistribute it and/or modify it under either the terms of the GPL, or the conditions below:
|
3
|
+
|
4
|
+
1. You may make and give away verbatim copies of the source form of the
|
5
|
+
software without restriction, provided that you duplicate all of the
|
6
|
+
original copyright notices and associated disclaimers.
|
7
|
+
|
8
|
+
2. You may modify your copy of the software in any way, provided that
|
9
|
+
you do at least ONE of the following:
|
10
|
+
|
11
|
+
a) place your modifications in the Public Domain or otherwise
|
12
|
+
make them Freely Available, such as by posting said
|
13
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
14
|
+
the author to include your modifications in the software.
|
15
|
+
|
16
|
+
b) use the modified software only within your corporation or
|
17
|
+
organization.
|
18
|
+
|
19
|
+
c) rename any non-standard executables so the names do not conflict
|
20
|
+
with standard executables, which must also be provided.
|
21
|
+
|
22
|
+
d) make other distribution arrangements with the author.
|
23
|
+
|
24
|
+
3. You may distribute the software in object code or executable
|
25
|
+
form, provided that you do at least ONE of the following:
|
26
|
+
|
27
|
+
a) distribute the executables and library files of the software,
|
28
|
+
together with instructions (in the manual page or equivalent)
|
29
|
+
on where to get the original distribution.
|
30
|
+
|
31
|
+
b) accompany the distribution with the machine-readable source of
|
32
|
+
the software.
|
33
|
+
|
34
|
+
c) give non-standard executables non-standard names, with
|
35
|
+
instructions on where to get the original software distribution.
|
36
|
+
|
37
|
+
d) make other distribution arrangements with the author.
|
38
|
+
|
39
|
+
4. You may modify and include the part of the software into any other
|
40
|
+
software (possibly commercial). But some files in the distribution
|
41
|
+
are not written by the author, so that they are not under this terms.
|
42
|
+
|
43
|
+
They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
|
44
|
+
files under the ./missing directory. See each file for the copying
|
45
|
+
condition.
|
46
|
+
|
47
|
+
5. The scripts and library files supplied as input to or produced as
|
48
|
+
output from the software do not automatically fall under the
|
49
|
+
copyright of the software, but belong to whomever generated them,
|
50
|
+
and may be sold commercially, and may be aggregated with this
|
51
|
+
software.
|
52
|
+
|
53
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
54
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
55
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
56
|
+
PURPOSE.
|
57
|
+
|
58
|
+
|
data/lib/data_view.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
module DataView
|
2
|
+
|
3
|
+
# DataView is intended to reduce coupling between the Controller and View layers in a MVC application. The Controller can send a DataView to the View layer. The View layer does not need to have access to the Model.
|
4
|
+
class DataView
|
5
|
+
class Row
|
6
|
+
public
|
7
|
+
include Enumerable
|
8
|
+
attr_accessor :data_view
|
9
|
+
def initialize(data_view, values = [])
|
10
|
+
@data_view = data_view
|
11
|
+
@values = values
|
12
|
+
end
|
13
|
+
def [](key)
|
14
|
+
return @values[get_index(key)]
|
15
|
+
end
|
16
|
+
def []=(key, value)
|
17
|
+
@values[get_index(key)] = value
|
18
|
+
end
|
19
|
+
def each
|
20
|
+
@values.each_with_index do |v, i|
|
21
|
+
yield(data_view.fields[i], v)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
def length
|
25
|
+
@values.length
|
26
|
+
end
|
27
|
+
private
|
28
|
+
def get_index(key)
|
29
|
+
return data_view.fields.index(key) if data_view.fields.include?(key)
|
30
|
+
raise 'key must either be an array index integer or a field key' unless key.respond_to?(:to_i)
|
31
|
+
return key
|
32
|
+
end
|
33
|
+
end
|
34
|
+
public
|
35
|
+
include Enumerable
|
36
|
+
attr_reader :fields, :titles, :delegates
|
37
|
+
# Initializes the DataView.
|
38
|
+
# ===Model
|
39
|
+
# The DataView supports a model that contains an array of hashes. The keys in these hashes much be symbols of the field names. This is based off of the ActiveRecord interface.
|
40
|
+
# ===Params
|
41
|
+
# Params is a symbol keyed Hash of parameters to be passed.
|
42
|
+
# ====:fields
|
43
|
+
# An array of the fields, on order, that will be used from the model. A field value should be a Symbol or a Proc that accepts the @model and row_index and returns the value to access the value.
|
44
|
+
# ====:titles
|
45
|
+
# A Hash of the titles for the fields. The field symbol is the key, and the title is the value.
|
46
|
+
# ====:values
|
47
|
+
# A hash of Procs that get nondefault values of a field in a particular row. By default, the value is taken by looking at the field in the model. The Proc must accept a Hash of parameters and return the transformed value. The Hash contains the following keys:
|
48
|
+
# * :sender - The DataView sending the call
|
49
|
+
# * :row_index - The Index of the current row.
|
50
|
+
# * :column_index - The Index of the current column.
|
51
|
+
# * :field - The field of the current value.
|
52
|
+
# ====:value_transforms
|
53
|
+
# A Hash of the delegates that will process the values. The field symbol is the key, and the Proc or array of Procs to transform the value. The Proc must accept a Hash of parameters and return the transformed value. The Hash contains the following keys:
|
54
|
+
# * :sender - The DataView sending the call
|
55
|
+
# * :row_index - The Index of the current row.
|
56
|
+
# * :column_index - The Index of the current column.
|
57
|
+
# * :value - The current value.
|
58
|
+
# * :field - The field of the current value.
|
59
|
+
def initialize(model, params = {})
|
60
|
+
@model = model.respond_to?(:each_index) ? model : [model]
|
61
|
+
|
62
|
+
# @fields is an ordered array of the fields that will be shown
|
63
|
+
@fields = get_param_value(params, :fields)
|
64
|
+
@fields = Array.new() if @fields == nil
|
65
|
+
|
66
|
+
# @titles is a hash with the field as the key and the title as the value
|
67
|
+
@titles = get_param_value(params, :titles)
|
68
|
+
@titles = Hash.new() if @titles == nil
|
69
|
+
|
70
|
+
# @values is a hash of Procs that get nondefault values of a field in a particular row. By default, the value is taken by looking at the field in the model.
|
71
|
+
@values = get_param_value(params, :values)
|
72
|
+
@values = Hash.new() if @values == nil
|
73
|
+
|
74
|
+
# @value_transforms is a hash with the field as the key and a Proc or array of procs that transforms the value into the proper format as the value
|
75
|
+
# The Proc that is the value must accept a hash that has the following keys:
|
76
|
+
# :sender, :row_index, :column_index, :value, :field
|
77
|
+
value_transforms = get_param_value(params, :value_transforms)
|
78
|
+
value_transforms = Hash.new() if value_transforms == nil
|
79
|
+
@value_transforms = format_value_transforms(value_transforms)
|
80
|
+
end
|
81
|
+
# Gets a particular row of the view.
|
82
|
+
def [](index)
|
83
|
+
get_view_row(index)
|
84
|
+
end
|
85
|
+
# The number of rows in the result.
|
86
|
+
def length
|
87
|
+
@model.length
|
88
|
+
end
|
89
|
+
# Iterates through each row of the view.
|
90
|
+
def each
|
91
|
+
@model.each_index do |row_index|
|
92
|
+
yield(get_view_row(row_index))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
# Iterates through each title of the fields.
|
96
|
+
def each_title
|
97
|
+
@fields.each do |field|
|
98
|
+
if @titles.include?(field)
|
99
|
+
yield(field, @titles[field])
|
100
|
+
else
|
101
|
+
yield(field, nil)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
# Iterates through each title of the fields with the index.
|
106
|
+
def each_title_with_index
|
107
|
+
i = 0
|
108
|
+
each_title do |f, t|
|
109
|
+
yield(f, t, i)
|
110
|
+
i = i + 1
|
111
|
+
end
|
112
|
+
end
|
113
|
+
private
|
114
|
+
def get_view_row(row_index)
|
115
|
+
model_row = @model[row_index]
|
116
|
+
view_row_values = []
|
117
|
+
@fields.each_with_index do |field, field_index|
|
118
|
+
if @values.include?(field)
|
119
|
+
actual_value = @values[field].call(@model, row_index, field)
|
120
|
+
else
|
121
|
+
actual_value = model_row[field]
|
122
|
+
end
|
123
|
+
view_value = actual_value
|
124
|
+
|
125
|
+
if @value_transforms.include?(field)
|
126
|
+
delegate_value = actual_value
|
127
|
+
@value_transforms[field].each do |delegate|
|
128
|
+
delegate_params = {
|
129
|
+
:sender => self,
|
130
|
+
:row_index => row_index,
|
131
|
+
:column_index => field_index,
|
132
|
+
:value => delegate_value,
|
133
|
+
:field => field
|
134
|
+
}
|
135
|
+
delegate_value = delegate.call(delegate_params)
|
136
|
+
end
|
137
|
+
view_value = delegate_value
|
138
|
+
end
|
139
|
+
view_row_values << view_value
|
140
|
+
end
|
141
|
+
Row.new(self, view_row_values)
|
142
|
+
end
|
143
|
+
def get_param_value(param, key)
|
144
|
+
return nil if param == nil
|
145
|
+
return param[key]
|
146
|
+
end
|
147
|
+
def format_value_transforms(delegates)
|
148
|
+
delegates.each do |k, *items|
|
149
|
+
delegates[k] = items.flatten
|
150
|
+
delegates[k].each do |d|
|
151
|
+
raise ":delegate must respond to call" unless d.respond_to?(:call)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
delegates
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
data/lib/dataview.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'data_view'
|
@@ -0,0 +1,138 @@
|
|
1
|
+
this_dir = File.dirname(__FILE__)
|
2
|
+
require this_dir << '/../lib/data_view'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class DataViewTest < Test::Unit::TestCase
|
6
|
+
include DataView
|
7
|
+
public
|
8
|
+
def test_brackets
|
9
|
+
do_test_brackets(mock_model)
|
10
|
+
do_test_brackets(singular_mock_model)
|
11
|
+
end
|
12
|
+
def test_each
|
13
|
+
do_test_each(mock_model)
|
14
|
+
do_test_each(singular_mock_model)
|
15
|
+
end
|
16
|
+
def test_each_title
|
17
|
+
do_test_each_title(mock_model)
|
18
|
+
do_test_each_title(singular_mock_model)
|
19
|
+
end
|
20
|
+
def test_each_title_with_index
|
21
|
+
do_test_each_title_with_index(mock_model)
|
22
|
+
do_test_each_title_with_index(singular_mock_model)
|
23
|
+
end
|
24
|
+
def test_length
|
25
|
+
assert_equal(mock_model.length, get_data_view(mock_model).length)
|
26
|
+
assert_equal(1, get_data_view(singular_mock_model).length)
|
27
|
+
end
|
28
|
+
private
|
29
|
+
def do_test_brackets(model)
|
30
|
+
data_view = get_data_view(model)
|
31
|
+
|
32
|
+
test_model = model.respond_to?(:each_index) ? model : [model]
|
33
|
+
test_model.each_with_index do |r, i|
|
34
|
+
fields.each_with_index do |f, j|
|
35
|
+
v = (f == :model_value_field) ? get_model_value(model, i, f) : r[f]
|
36
|
+
assert_equal(expected_altered_value(v), data_view[i][f])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
def do_test_each(model)
|
41
|
+
data_view = get_data_view(model)
|
42
|
+
data_view.each_with_index do |row, i|
|
43
|
+
expected_row = model.respond_to?(:each_index) ? model[i] : model
|
44
|
+
assert_equal(expected_row.length, row.to_a.length)
|
45
|
+
|
46
|
+
expected_row.each do |k, expected_value|
|
47
|
+
expected_value = get_model_value(model, i, k) if k == :model_value_field
|
48
|
+
assert_equal(expected_altered_value(expected_value), row[k])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
def do_test_each_title(model)
|
53
|
+
data_view = get_data_view(model)
|
54
|
+
i = 0
|
55
|
+
data_view.each_title do |f, t|
|
56
|
+
assert_equal(titles[f], t)
|
57
|
+
i = i + 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
def do_test_each_title_with_index(model)
|
61
|
+
data_view = get_data_view(model)
|
62
|
+
ei = 0
|
63
|
+
data_view.each_title_with_index do |f, t, i|
|
64
|
+
assert_equal(titles[fields[ei]], t)
|
65
|
+
assert_equal(ei, i)
|
66
|
+
ei = ei + 1
|
67
|
+
end
|
68
|
+
end
|
69
|
+
def expected_altered_value(v)
|
70
|
+
"altered " << v
|
71
|
+
end
|
72
|
+
def get_data_view(model)
|
73
|
+
DataView.new(
|
74
|
+
model,
|
75
|
+
:fields => fields,
|
76
|
+
:titles => titles,
|
77
|
+
:values => values,
|
78
|
+
:value_transforms => value_transforms
|
79
|
+
)
|
80
|
+
end
|
81
|
+
def get_model_value_method
|
82
|
+
return @get_model_value_method if defined?(@get_model_value_method)
|
83
|
+
@get_model_value_method = method(:get_model_value)
|
84
|
+
end
|
85
|
+
def get_model_value(model, row_index, field)
|
86
|
+
row_index.to_s << ' : Custom ' << field.to_s
|
87
|
+
end
|
88
|
+
def fields
|
89
|
+
return @fields if defined?(@fields)
|
90
|
+
@fields = [:model_value_field , :field1, :field2, :field3]
|
91
|
+
end
|
92
|
+
def titles
|
93
|
+
return @titles if defined?(@titles)
|
94
|
+
t = Hash.new()
|
95
|
+
fields.each do |f|
|
96
|
+
t[f] = f.to_s << ' Title'
|
97
|
+
end
|
98
|
+
@titles = t
|
99
|
+
end
|
100
|
+
def singular_mock_model
|
101
|
+
return @singular_mock_model if defined?(@singular_mock_model)
|
102
|
+
@singular_mock_model = get_mock_model_row(0)
|
103
|
+
end
|
104
|
+
def mock_model
|
105
|
+
return @mock_model if defined?(@mock_model)
|
106
|
+
m = Array.new
|
107
|
+
(0..2).each do |i|
|
108
|
+
row = get_mock_model_row(i)
|
109
|
+
m << row
|
110
|
+
end
|
111
|
+
@mock_model = m
|
112
|
+
end
|
113
|
+
def get_mock_model_row(i)
|
114
|
+
row = Hash.new
|
115
|
+
fields.each do |f|
|
116
|
+
next if f.respond_to?(:call)
|
117
|
+
row[f] = i.to_s << ' : ' << f.to_s
|
118
|
+
end
|
119
|
+
row
|
120
|
+
end
|
121
|
+
def values
|
122
|
+
return @values if defined?(@values)
|
123
|
+
v = Hash.new
|
124
|
+
v[:model_value_field] = get_model_value_method
|
125
|
+
@values = v
|
126
|
+
end
|
127
|
+
def value_transforms
|
128
|
+
return @value_transforms if defined?(@value_transforms)
|
129
|
+
t = Hash.new()
|
130
|
+
fields.each do |f|
|
131
|
+
t[f] = lambda { |h|
|
132
|
+
'altered ' << h[:value].to_s
|
133
|
+
}
|
134
|
+
end
|
135
|
+
@value_transforms = t
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
metadata
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: dataview
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2005-07-25 00:00:00 -07:00
|
8
|
+
summary: Data View is a library that creates a view of a data model. The view can transform the data of the data model without changing the data. Supports ActiveRecord models and other data models that have a similar interface.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: brian.takita@gmail.com
|
12
|
+
homepage: http://DataView.rubyforge.org
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
authors:
|
30
|
+
- Brian Takita
|
31
|
+
files:
|
32
|
+
- test/tc_data_view.rb
|
33
|
+
- test/ts_data_view.rb
|
34
|
+
- lib/dataview.rb
|
35
|
+
- lib/data_view.rb
|
36
|
+
- README
|
37
|
+
test_files:
|
38
|
+
- test/ts_data_view.rb
|
39
|
+
rdoc_options: []
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README
|
42
|
+
executables: []
|
43
|
+
extensions: []
|
44
|
+
requirements: []
|
45
|
+
dependencies: []
|