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.
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: []