data-writer 0.9.0
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/Gemfile +2 -0
- data/README.md +59 -0
- data/data-writer.gemspec +16 -0
- data/lib/data-writer.rb +108 -0
- metadata +82 -0
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
data-writer
|
|
2
|
+
===========
|
|
3
|
+
|
|
4
|
+
Normally you can only read from DATA but with data-writer you can also write to it. This allows you to easily persist data in a source file.
|
|
5
|
+
|
|
6
|
+
###Installation
|
|
7
|
+
|
|
8
|
+
gem install data-writer
|
|
9
|
+
|
|
10
|
+
###Usage
|
|
11
|
+
|
|
12
|
+
Here is a simple example program that keeps track of how many times it has been executed and stores this as a YAML file in DATA.
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
require 'data-writer'
|
|
16
|
+
require 'yaml'
|
|
17
|
+
|
|
18
|
+
store = YAML.load(DATA.read)
|
|
19
|
+
puts "run = #{store['run']}"
|
|
20
|
+
store["run"] += 1
|
|
21
|
+
|
|
22
|
+
DATAWriter.file("w+") do |w|
|
|
23
|
+
w.write(store.to_yaml)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
__END__
|
|
27
|
+
---
|
|
28
|
+
run: 1
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Each time this program is run it will increment run by 1 and persist the result in the YAML hash.
|
|
32
|
+
|
|
33
|
+
###API
|
|
34
|
+
|
|
35
|
+
__DATAWriter.file(mode_string, opt = {})__
|
|
36
|
+
|
|
37
|
+
A factory method that makes file objects which can write to data.
|
|
38
|
+
mode_string and opt are the same as for File.new.
|
|
39
|
+
If this method is called with a block it behaves as File.open and if it is called without
|
|
40
|
+
a block it returns a File object as in File.new.
|
|
41
|
+
|
|
42
|
+
Example:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
# append to DATA
|
|
46
|
+
require 'data-writer'
|
|
47
|
+
|
|
48
|
+
appender = DATAWriter.file("a")
|
|
49
|
+
appender.write " my dear Watson"
|
|
50
|
+
appender.close # DATA.read => "Elementary my dear Watson"
|
|
51
|
+
|
|
52
|
+
__END__
|
|
53
|
+
Elementary
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
If this method is called and DATA is not defined then it will raise a DATANotFoundError exception.
|
|
57
|
+
The file objects returned by this method have their #rewind method changed so that it seeks back to
|
|
58
|
+
the start of DATA, and not back to the start of the file.
|
|
59
|
+
|
data/data-writer.gemspec
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = 'data-writer'
|
|
3
|
+
s.version = '0.9.0'
|
|
4
|
+
s.date = '2012-07-15'
|
|
5
|
+
s.summary = "Allows you to write to DATA"
|
|
6
|
+
s.description = "Normally you can only read from DATA but with data-writer you can also write to it. This allows you to easily persist data in a source file."
|
|
7
|
+
s.authors = ["Kalle Lindstrom"]
|
|
8
|
+
s.email = ["lindstrom.kalle@gmail.com"]
|
|
9
|
+
s.homepage = "https://github.com/kl/data-writer"
|
|
10
|
+
s.files = %w[lib/data-writer.rb README.md data-writer.gemspec Gemfile]
|
|
11
|
+
s.require_paths = ['lib']
|
|
12
|
+
s.has_rdoc = false
|
|
13
|
+
|
|
14
|
+
s.add_development_dependency('rake')
|
|
15
|
+
s.add_development_dependency('minitest')
|
|
16
|
+
end
|
data/lib/data-writer.rb
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
|
|
2
|
+
class DATAWriter
|
|
3
|
+
|
|
4
|
+
class DATANotFoundError < StandardError; end
|
|
5
|
+
|
|
6
|
+
#
|
|
7
|
+
# The position in the file where DATA starts (line after __END__)
|
|
8
|
+
#
|
|
9
|
+
def self.data_start_pos
|
|
10
|
+
@data_start_pos
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
#
|
|
14
|
+
# Factory method for DATA writers. Works simliar to File.new.
|
|
15
|
+
#
|
|
16
|
+
def self.file(mode, opt={})
|
|
17
|
+
check_DATA_defined # raises an exception if DATA is not defined.
|
|
18
|
+
data_path = File.expand_path(DATA.path)
|
|
19
|
+
|
|
20
|
+
if mode =~ /w/ # if we have a "w" we first need to delete everything after __END__.
|
|
21
|
+
clear_end
|
|
22
|
+
mode.include?("b") ? m = "rb+" : m = "r+" # the actual mode will be rb+ or r+.
|
|
23
|
+
file = create_file(data_path, m, opt)
|
|
24
|
+
else
|
|
25
|
+
file = create_file(data_path, mode, opt)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
@data_start_pos = scan_data_pos # remeber the current position of __END__.
|
|
29
|
+
file.pos = @data_start_pos # sets the file pos to the line after __END__.
|
|
30
|
+
enhanced = enhance_file(file) # adds specialized methods for this object.
|
|
31
|
+
|
|
32
|
+
if block_given?
|
|
33
|
+
yield(enhanced)
|
|
34
|
+
enhanced.close
|
|
35
|
+
else
|
|
36
|
+
enhanced
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
#
|
|
41
|
+
# Helper method to create a file that works in both 1.8 and 1.9.
|
|
42
|
+
#
|
|
43
|
+
def self.create_file(path, mode_string, opt = {})
|
|
44
|
+
if RUBY_VERSION =~ /(1\.9)|(19)/
|
|
45
|
+
File.new(path, mode_string, opt)
|
|
46
|
+
else
|
|
47
|
+
File.new(path, mode_string)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
private_class_method :create_file
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
# Deletes everything after __END__. This is used to simulate the "w" permission mode.
|
|
54
|
+
#
|
|
55
|
+
def self.clear_end
|
|
56
|
+
file_path = File.expand_path(DATA.path)
|
|
57
|
+
file_content = File.read(file_path)
|
|
58
|
+
new_content = file_content[/.+?^__END__$/m] + "\n" # everything up to an including __END__.
|
|
59
|
+
|
|
60
|
+
File.open(file_path, "w") { |f| f.write(new_content) }
|
|
61
|
+
end
|
|
62
|
+
private_class_method :clear_end
|
|
63
|
+
|
|
64
|
+
#
|
|
65
|
+
# Finds the position in the file after __END__. DATA.pos isn't used because of
|
|
66
|
+
# problems when opening the file in "w" mode.
|
|
67
|
+
#
|
|
68
|
+
def self.scan_data_pos
|
|
69
|
+
source_file = File.new(File.expand_path($0))
|
|
70
|
+
|
|
71
|
+
until source_file.eof?
|
|
72
|
+
line = source_file.gets
|
|
73
|
+
if line =~ /^^__END__$/
|
|
74
|
+
pos = source_file.pos
|
|
75
|
+
source_file.close
|
|
76
|
+
return pos
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
source_file.close
|
|
80
|
+
raise DATANotFoundError, "DATA object does not exist. Ensure that the file has __END__"
|
|
81
|
+
end
|
|
82
|
+
private_class_method :scan_data_pos
|
|
83
|
+
|
|
84
|
+
#
|
|
85
|
+
# Adds specialized methods to the DATA writer object.
|
|
86
|
+
#
|
|
87
|
+
def self.enhance_file(object)
|
|
88
|
+
|
|
89
|
+
def object.rewind # so that #rewind will go back to __END__ and not the beginning of the file.
|
|
90
|
+
self.pos = DATAWriter.data_start_pos
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
object
|
|
94
|
+
end
|
|
95
|
+
private_class_method :enhance_file
|
|
96
|
+
|
|
97
|
+
#
|
|
98
|
+
# Raises a DATANotFoundError exception if DATA is not defined.
|
|
99
|
+
#
|
|
100
|
+
def self.check_DATA_defined
|
|
101
|
+
begin
|
|
102
|
+
DATA
|
|
103
|
+
rescue NameError
|
|
104
|
+
raise DATANotFoundError, "DATA object does not exist. Ensure that the file has __END__"
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
private_class_method :check_DATA_defined
|
|
108
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: data-writer
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.9.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Kalle Lindstrom
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-07-15 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: rake
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: minitest
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :development
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ! '>='
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0'
|
|
46
|
+
description: Normally you can only read from DATA but with data-writer you can also
|
|
47
|
+
write to it. This allows you to easily persist data in a source file.
|
|
48
|
+
email:
|
|
49
|
+
- lindstrom.kalle@gmail.com
|
|
50
|
+
executables: []
|
|
51
|
+
extensions: []
|
|
52
|
+
extra_rdoc_files: []
|
|
53
|
+
files:
|
|
54
|
+
- lib/data-writer.rb
|
|
55
|
+
- README.md
|
|
56
|
+
- data-writer.gemspec
|
|
57
|
+
- Gemfile
|
|
58
|
+
homepage: https://github.com/kl/data-writer
|
|
59
|
+
licenses: []
|
|
60
|
+
post_install_message:
|
|
61
|
+
rdoc_options: []
|
|
62
|
+
require_paths:
|
|
63
|
+
- lib
|
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
|
+
none: false
|
|
66
|
+
requirements:
|
|
67
|
+
- - ! '>='
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '0'
|
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
|
+
none: false
|
|
72
|
+
requirements:
|
|
73
|
+
- - ! '>='
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
requirements: []
|
|
77
|
+
rubyforge_project:
|
|
78
|
+
rubygems_version: 1.8.24
|
|
79
|
+
signing_key:
|
|
80
|
+
specification_version: 3
|
|
81
|
+
summary: Allows you to write to DATA
|
|
82
|
+
test_files: []
|