collection 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.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Michael Aufreiter
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,42 @@
1
+ Collection API
2
+ ================================================================================
3
+
4
+ A Ruby API for the [Unveil.js](http://github.com/michael/unveil/) collection
5
+ interface. Useful for exporting all kinds of data in a uniform Collection format.
6
+
7
+
8
+ Usage
9
+ --------------------------------------------------------------------------------
10
+
11
+ c = Collection.new
12
+ c.property(:customer, {:name => "Customer", :type => String, :unique => true })
13
+ c.property(:product, {:name => "Product", :type => String, :unique => true })
14
+ c.property(:quantity, {:name => "Salesman", :type => Numeric, :unique => true })
15
+ c.property(:price, {:name => "Price", :type => Numeric, :unique => true })
16
+
17
+ c.add("IO47181", {
18
+ :customer => "John Smith",
19
+ :product => "XT52",
20
+ :quantity => 21,
21
+ :price => 231.5
22
+ })
23
+
24
+ c.to_json => A JSON string that conforms to an Unveil.js Collection
25
+ c.to_csv => Plain old CSV representation, if your clients can't get around Excel :/
26
+
27
+
28
+ Note on Patches/Pull Requests
29
+ --------------------------------------------------------------------------------
30
+
31
+ * Fork the project.
32
+ * Make your feature addition or bug fix.
33
+ * Add tests for it. This is important so I don't break it in a
34
+ future version unintentionally.
35
+ * Commit, do not mess with rakefile, version, or history.
36
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
37
+ * Send me a pull request. Bonus points for topic branches.
38
+
39
+ Copyright
40
+ --------------------------------------------------------------------------------
41
+
42
+ Copyright (c) 2010 Michael Aufreiter. See LICENSE for details.
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "collection"
8
+ gem.summary = %Q{A Ruby API for the Unveil.js collection interface}
9
+ gem.description = %Q{}
10
+ gem.email = "ma@zive.at"
11
+ gem.homepage = "http://github.com/michael/collection"
12
+ gem.authors = ["Michael Aufreiter"]
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/test_*.rb'
24
+ test.verbose = true
25
+ end
26
+
27
+ begin
28
+ require 'rcov/rcovtask'
29
+ Rcov::RcovTask.new do |test|
30
+ test.libs << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+ rescue LoadError
35
+ task :rcov do
36
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
+ end
38
+ end
39
+
40
+ task :test => :check_dependencies
41
+
42
+ task :default => :test
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "collection #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,51 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{collection}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Aufreiter"]
12
+ s.date = %q{2010-07-27}
13
+ s.description = %q{}
14
+ s.email = %q{ma@zive.at}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.md",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "collection.gemspec",
27
+ "lib/collection.rb",
28
+ "test/helper.rb",
29
+ "test/test_collection.rb"
30
+ ]
31
+ s.homepage = %q{http://github.com/michael/collection}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.6}
35
+ s.summary = %q{A Ruby API for the Unveil.js collection interface}
36
+ s.test_files = [
37
+ "test/helper.rb",
38
+ "test/test_collection.rb"
39
+ ]
40
+
41
+ if s.respond_to? :specification_version then
42
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
43
+ s.specification_version = 3
44
+
45
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
46
+ else
47
+ end
48
+ else
49
+ end
50
+ end
51
+
@@ -0,0 +1,184 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+ require 'date'
4
+ require 'fastercsv'
5
+
6
+ # Collection API
7
+ # ==============================================================================
8
+ #
9
+ # Usage:
10
+ #
11
+ # c = Collection.new
12
+ # c.property(:customer, {:name => "Customer", :type => String, :unique => true })
13
+ # c.property(:product, {:name => "Product", :type => String, :unique => true })
14
+ # c.property(:quantity, {:name => "Salesman", :type => Numeric, :unique => true })
15
+ # c.property(:price, {:name => "Price", :type => Numeric, :unique => true })
16
+ #
17
+ # c.add("IO47181", {
18
+ # :customer => "John Smith",
19
+ # :product => "XT52",
20
+ # :quantity => 21,
21
+ # :price => 231.5
22
+ # })
23
+ #
24
+ # c.to_json
25
+ # c.to_csv
26
+ #
27
+
28
+
29
+ class Collection
30
+
31
+ class PropertyExists < StandardError ; end
32
+ class PropertyNotFound < StandardError ; end
33
+
34
+
35
+ module Formatters
36
+ def self.number_to_currency(number, options = {})
37
+ precision = options[:precision] || 2
38
+ unit = options[:unit] || ""
39
+ separator = precision > 0 ? options[:separator] || "." : ""
40
+ delimiter = options[:delimiter] || ""
41
+ format = options[:format] || "%u%n"
42
+ begin
43
+ parts = number_with_precision(number, precision).split('.')
44
+ format.gsub(/%n/, number_with_delimiter(parts[0], delimiter) + separator + parts[1].to_s).gsub(/%u/, unit)
45
+ rescue
46
+ number
47
+ end
48
+ end
49
+
50
+ def self.number_with_delimiter(number, delimiter=",", separator=".")
51
+ begin
52
+ parts = number.to_s.split('.')
53
+ parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
54
+ parts.join separator
55
+ rescue
56
+ number
57
+ end
58
+ end
59
+
60
+ def self.number_with_precision(number, precision=3)
61
+ "%01.#{precision}f" % ((Float(number) * (10 ** precision)).round.to_f / 10 ** precision)
62
+ rescue
63
+ number
64
+ end
65
+ end
66
+
67
+ class Property
68
+ attr_accessor :key, :name, :type, :descr, :collection
69
+
70
+ def initialize(collection, key, options)
71
+ @collection, @key = collection, key
72
+ @name = options[:name]
73
+ @type = options[:type]
74
+ @descr = options[:descr]
75
+ @unique = options[:unique]
76
+ end
77
+
78
+ def type_as_string
79
+ if type.kind_of?(Numeric)
80
+ "number"
81
+ elsif type.kind_of?(Date)
82
+ "date"
83
+ else
84
+ "string"
85
+ end
86
+ end
87
+
88
+ def to_hash
89
+ {
90
+ :name => @name,
91
+ :type => type_as_string,
92
+ :descr => @descr.to_s,
93
+ :unique => @unique
94
+ }
95
+ end
96
+
97
+ def unique?
98
+ @unique
99
+ end
100
+ end
101
+
102
+ class Item
103
+ attr_accessor :values
104
+
105
+ def initialize(collection, key, values)
106
+ @collection, @key, @values = collection, key, values
107
+ end
108
+
109
+ def value(property_key)
110
+ raise PropertyNotFound unless @collection.properties.key?(property_key)
111
+ @values[property_key]
112
+ end
113
+ end
114
+
115
+ attr_reader :properties
116
+ attr_reader :items
117
+
118
+ def initialize
119
+ @properties = {}
120
+ @items = {}
121
+
122
+ # preserve the insertion order
123
+ @property_keys = []
124
+ @item_keys = []
125
+ end
126
+
127
+ def property(key, options)
128
+ @properties[key] = Property.new(self, key, options)
129
+ @property_keys << key
130
+ end
131
+
132
+ def add(key, item)
133
+ @items[key] = Item.new(self, key, item)
134
+ @item_keys << key
135
+ end
136
+
137
+ def remove(key)
138
+ @items.delete(key)
139
+ end
140
+
141
+ def to_json
142
+ result = {:properties => {}, :items => {}}
143
+
144
+ @property_keys.each do |key|
145
+ result[:properties][key] = @properties[key].to_hash
146
+ end
147
+
148
+ @item_keys.each do |key|
149
+ result[:items][key] = @items[key].values
150
+ end
151
+
152
+ JSON.pretty_generate(result)
153
+ end
154
+
155
+ def to_csv(options = { :col_sep => ',', :number_delimiter => '', :number_separator => '.' })
156
+ csv_options = options.clone
157
+ csv_options.delete(:number_delimiter)
158
+ csv_options.delete(:number_separator)
159
+
160
+ FasterCSV.generate(csv_options) do |csv|
161
+ # Add headers
162
+ headers = []
163
+ @property_keys.each do |key|
164
+ headers << @properties[key].name
165
+ end
166
+ csv << headers
167
+
168
+ # Add data rows
169
+ @item_keys.each do |item_key|
170
+ row_data = []
171
+ @property_keys.each do |property_key|
172
+ val = @items[item_key].value(property_key)
173
+ if val.kind_of?(Numeric)
174
+ row_data << Formatters.number_to_currency(val, :separator => options[:number_separator], :delimiter => options[:number_delimiter])
175
+ else
176
+ row_data << val
177
+ end
178
+ end
179
+ csv << row_data
180
+ end
181
+
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ require 'collection'
7
+
8
+ class Test::Unit::TestCase
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestCollection < Test::Unit::TestCase
4
+ def test_something_for_real
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: collection
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Michael Aufreiter
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-27 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: ""
22
+ email: ma@zive.at
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - LICENSE
29
+ - README.md
30
+ files:
31
+ - .document
32
+ - .gitignore
33
+ - LICENSE
34
+ - README.md
35
+ - Rakefile
36
+ - VERSION
37
+ - collection.gemspec
38
+ - lib/collection.rb
39
+ - test/helper.rb
40
+ - test/test_collection.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/michael/collection
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --charset=UTF-8
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.3.6
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: A Ruby API for the Unveil.js collection interface
71
+ test_files:
72
+ - test/helper.rb
73
+ - test/test_collection.rb