data-writer 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/Gemfile +2 -0
  2. data/README.md +59 -0
  3. data/data-writer.gemspec +16 -0
  4. data/lib/data-writer.rb +108 -0
  5. metadata +82 -0
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
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
+
@@ -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
@@ -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: []