roject 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 208a333165807d295fc40b90cfddc1431721cfb4
4
- data.tar.gz: b16f2f8863a41781887024765afbe592ad461503
3
+ metadata.gz: ad19a40c37044d2c05db12edde1618900c5f2897
4
+ data.tar.gz: 4a7050a650334712f4d7b96b4b164e6229aa3404
5
5
  SHA512:
6
- metadata.gz: b0adfc93d7dc2c1add24a6537b217821a30a45f3e4b241036e55229c8a4fbe49169980af3fb1041fe3da14a74ec569ed16edbafc85e97f4fad040dc157747c6c
7
- data.tar.gz: 2e395a73765997c907e5ebd83b0805c1e5abcf6384cfdf329a8a0328c03c48f4038bde95ab73d28b343e25baa534be836855d52b19295c8617b9e5f7a0f5c6fc
6
+ metadata.gz: ba8034309255d69673d30b41c6044fe3c5369ed5fa73003139e58043bc939e43a6f41d258ed07aa422c28645035d0ddf1d0fcddae7382ec572536ea3d7868cee
7
+ data.tar.gz: 9757271c4518331712df7265bd6f2b00e1b01b23886a8ab20712da7a40141a57b9ed779955a1fefcbee80f225698694e4253349328cc8d53dee1fc8936ec413f
@@ -0,0 +1,37 @@
1
+ # Config
2
+ config project_name: "Dre",
3
+ author: "Anshul Kharbanda",
4
+ created: "7 - 23 - 2016",
5
+ short_description: "Forgot about Dre.",
6
+ long_description: "Nowadays everybody wanna talk like" \
7
+ " they got somethin' to say but nothin' comes out" \
8
+ " when they move their lips just a bunch of gibberish" \
9
+ " and they all acting like they forgot about Dre."
10
+
11
+ =begin
12
+
13
+ #---------------------------MAKERS---------------------------
14
+
15
+ # Header file
16
+ file :header,
17
+ path: "include/@(project_name)/@(path)",
18
+ template: "header.general",
19
+ extension: "h"
20
+
21
+ # Source file
22
+ file :source,
23
+ path: "src/@(path)",
24
+ template: "source.general",
25
+ extension: "cpp"
26
+
27
+ # Module includes a source and include
28
+ task :module do |args|
29
+ # Add header id
30
+ args[:header_id] = c_header_id(args[:path])
31
+
32
+ # Create source and header
33
+ make :header, args
34
+ make :source, args
35
+ end
36
+
37
+ =end
@@ -35,7 +35,7 @@ module Roject
35
35
  # Parameter: project - the project running the task
36
36
  # Parameter: args - the args being used to run the task
37
37
  def make project, args
38
- project.instance_exec project.hash.merge(args), &@block
38
+ project.instance_exec project.config.merge(args), &@block
39
39
  end
40
40
  end
41
41
 
@@ -50,9 +50,9 @@ module Roject
50
50
  # Initializes a FileMaker from the given hash
51
51
  #
52
52
  # Parameter: hash - the hash to parse
53
- def initialize hash
53
+ def initialize project, hash
54
54
  @path = General::GTemplate.new hash[:path]
55
- @template = General::GIO.load hash[:template]
55
+ @template = General::GIO.load "#{project.config[:directory][:templates]}/#{hash[:template]}"
56
56
  @extension = hash[:extension]
57
57
  end
58
58
 
@@ -62,7 +62,7 @@ module Roject
62
62
  # Parameter: args - the args being used to create the file
63
63
  def make project, args
64
64
  # merge args with project
65
- args.merge! project.hash
65
+ args.merge! project.config
66
66
 
67
67
  # Get path
68
68
  path = "#{@path.apply(args)}.#{@extension}"
data/lib/project.rb CHANGED
@@ -12,9 +12,8 @@ Created: 7 - 8 - 2016
12
12
  =end
13
13
 
14
14
  # Other modules
15
- require_relative "loadsaveable"
16
15
  require_relative "helpers"
17
- require_relative "maker"
16
+ require_relative "makers"
18
17
 
19
18
  # Roject is a programming project manager written in Ruby.
20
19
  #
@@ -27,60 +26,77 @@ module Roject
27
26
  # Created: 7 - 10 - 2016
28
27
  class Project
29
28
  # Includes
30
- include LoadSaveable
31
29
  include Helpers
32
30
 
33
- # Creates a Project with the given data hash
31
+ # Default configuration
32
+ CONFIG_DEFAULT = {
33
+ project_name: "[project-name]",
34
+ author: "[author]",
35
+ created: "[created]",
36
+ short_description: "[short_description]",
37
+ long_description: "[long_description]",
38
+ directory: {
39
+ templates: "_templates"
40
+ }
41
+ }
42
+
43
+ # Loads a Project from the project file with the given filename
44
+ #
45
+ # Parameter: filename - the name of the file to parse
34
46
  #
35
- # Parameter: hash - the data to be contained in the project
36
- def initialize hash={}
37
- @project = hash
38
- @makers = {}
47
+ # Return: Project loaded from the file
48
+ def self.load filename
49
+ project = Roject::Project.new
50
+ project.instance_eval(IO.read(filename))
51
+ return project
39
52
  end
40
53
 
41
- # Returns a hash of the data contained in the project
42
- #
43
- # Return: a hash of the data contained in the project
44
- def hash; @project; end
54
+ #----------------------------------INIT AND CONFIG----------------------------------
45
55
 
46
- # Attributes part of Project
47
- get :project_name,
48
- :author,
49
- :created,
50
- :short_description,
51
- :long_description,
52
- :directories
56
+ # Called upon the initialization of a Project
57
+ # Creates config and makers hashes
58
+ def initialize; @config = CONFIG_DEFAULT; @makers = {}; end
53
59
 
54
- # Loads the makers in the file with the given filename
60
+ # If a hash is given, sets the Project configuration to the hash.
61
+ # Else, returns the configuration of the Project.
62
+ #
63
+ # Parameter: hash - the hash to configure the project with
55
64
  #
56
- # Parameter: filename - the name of the file to read
57
- def load_makers(filename); instance_eval(IO.read(filename)); end
65
+ # Return: the configuration of the Project
66
+ def config(hash=nil); hash and @config.merge!(hash) or return @config; end
67
+
68
+ #-------------------------------------MAKERS-----------------------------------------
58
69
 
59
70
  # Runs the maker of the given name with the given args
60
71
  #
61
72
  # Parameter: name - the name of the maker to run
62
73
  # Parameter: args - the args to pass to the file
63
- def make name, args
64
- @makers[name].make(self, args)
74
+ def make(name, args)
75
+ if @makers.has_key? name
76
+ @makers[name].make self, args
77
+ else
78
+ raise RuntimeError, "Undefied maker #{name}"
79
+ end
65
80
  end
66
81
 
67
82
  # Creates a file maker with the given name and hash
68
83
  #
69
84
  # Parameter: name - the name of the maker
70
85
  # Parameter: hash - the hash arguments of the maker
71
- def file name, hash
72
- @makers[name] = FileMaker.new(hash)
86
+ def file(name, hash)
87
+ unless @makers.has_key? name
88
+ @makers[name] = FileMaker.new self, hash
89
+ end
73
90
  end
74
91
 
75
- # Adds the recipie specified by the given name and block
76
- # to the makers table
92
+ # Creates a task maker with the given name and block
77
93
  #
78
94
  # Parameter: name - the name of the recipie
79
95
  # Parameter: block - the recipie block
80
- #
81
- # Throw: RuntimeError - if the name is already defined as a filetype
82
- def task name, &block
83
- @makers[name] = TaskMaker.new &block
96
+ def task(name, &block);
97
+ unless @makers.has_key? name
98
+ @makers[name] = TaskMaker.new &block
99
+ end
84
100
  end
85
101
  end
86
102
  end
data/lib/roject.rb CHANGED
@@ -20,5 +20,5 @@ require_relative "project"
20
20
  # Created: 7 - 8 - 2016
21
21
  module Roject
22
22
  # The Version of Roject
23
- VERSION = "0.5.0"
23
+ VERSION = "0.6.0"
24
24
  end
data/spec/project_spec.rb CHANGED
@@ -23,65 +23,187 @@ require_relative "spec_require"
23
23
  describe Roject::Project do
24
24
  # Do before
25
25
  before :all do
26
- Dir.chdir "exp/project"
27
- @project = Roject::Project.load "project.yaml"
26
+ Dir.chdir "exp/project"
27
+ @project = Roject::Project.new
28
+ @config = Roject::Project::CONFIG_DEFAULT.merge({
29
+ project_name: "Foo",
30
+ author: "Anshul Kharbanda",
31
+ created: "7 - 23 - 2016",
32
+ short_description: "Foo bar",
33
+ long_description: "Foo bar baz ju lar laz nu kar kaz"
34
+ })
28
35
  end
29
36
 
30
- # Describe Roject::Project#load_recipies
37
+ # Describe Roject::Project#config
38
+ #
39
+ # If a hash is given, sets the Project configuration to the hash.
40
+ # Else, returns the configuration of the Project.
41
+ #
42
+ # Parameter: hash - the hash to configure the project with
43
+ #
44
+ # Return: the configuration of the Project
45
+ describe '#config' do
46
+ context 'with no arguments given' do
47
+ it 'returns the configuration of the Project' do
48
+ expect(@project.config).to eql Roject::Project::CONFIG_DEFAULT
49
+ end
50
+ end
51
+
52
+ context 'with hash given' do
53
+ it 'configures the Project with the given hash' do
54
+ expect{@project.config(@config)}.not_to raise_error
55
+ expect(@project.config).to eql @config
56
+ end
57
+ end
58
+ end
59
+
60
+ # Describe Roject::Project::load
61
+ #
62
+ # Loads a Project from the project file with the given filename
31
63
  #
32
- # Loads the recipies in the file with the given filename
64
+ # Parameter: filename - the name of the file to parse
33
65
  #
34
- # Parameter: filename - the name of the file to read
35
- describe '#load_recipies' do
36
- it 'reads a recipies file and evaluates it in the context of the Project' do
37
- expect { @project.load_makers("makers.rb") }.not_to raise_error
66
+ # Return: Project loaded from the file
67
+ describe '::load' do
68
+ it 'loads a project from the given filename' do
69
+ expect{@project = Roject::Project.load "project.rb"}.not_to raise_error
70
+ expect(@project).to be_an_instance_of Roject::Project
38
71
  end
39
72
  end
40
73
 
41
- # Describe Roject::Project#make
74
+ # Describe Roject::Project makers
42
75
  #
43
- # Runs the maker of the given name with the given args
76
+ # The system of automating tasks in Roject
44
77
  #
45
- # Parameter: name - the name of the maker to run
46
- # Parameter: args - the args to pass to the file
47
- describe '#make' do
78
+ # Author: Anshul Kharbanda
79
+ # Created: 7 - 24 - 2016
80
+ describe 'makers' do
81
+ # Before all
48
82
  before :all do
49
83
  @path = "path/to/file"
50
84
 
85
+ # ----------------------FILE INFO----------------------
86
+
51
87
  @header = {
52
- type: :header,
53
- out: "include/#{@project.project_name}/#{@path}.h",
88
+ name: :header,
89
+ path: "include/@(project_name)/@(path)",
90
+ template: "header.general",
91
+ extension: "h",
92
+ out: "include/#{@project.config[:project_name]}/#{@path}.h",
54
93
  text: IO.read("output/testheader.h")
55
94
  }
56
95
 
57
96
  @source = {
58
- type: :source,
97
+ name: :source,
98
+ path: "src/@(path)",
99
+ template: "source.general",
100
+ extension: "cpp",
59
101
  out: "src/#{@path}.cpp",
60
102
  text: IO.read("output/testsource.cpp")
61
103
  }
104
+
105
+ # ----------------------TASK INFO----------------------
106
+
107
+ @module = {
108
+ name: :module,
109
+ block: Proc.new do |args|
110
+ args[:header_id] = c_header_id(args[:path])
111
+
112
+ make :header, args
113
+ make :source, args
114
+ end
115
+ }
62
116
  end
63
117
 
64
- # Creating filetype
65
- context 'with a file maker name given' do
66
- it 'creates a file of the given type with the given arguments' do
67
- @project.make @header[:type], path: @path, header_id: @project.c_header_id(@path)
68
- expect(File).to be_file(@header[:out])
69
- expect(IO.read(@header[:out])).to eql @header[:text]
118
+ # Describe Roject::Project#file
119
+ #
120
+ # Creates a file maker with the given name and hash
121
+ #
122
+ # Parameter: name - the name of the maker
123
+ # Parameter: hash - the hash arguments of the maker
124
+ describe '#file' do
125
+ it 'creates a file maker with the given name and hash of arguments' do
126
+ # Each file type
127
+ [@header, @source].each do |ft|
128
+ # Create filemaker
129
+ @project.file ft[:name], ft
130
+
131
+ # Get Filemaker
132
+ fmkr = @project.instance_variable_get(:@makers)[ft[:name]]
133
+ expect(fmkr).to be_an_instance_of Roject::FileMaker
134
+
135
+ # Path
136
+ expect(fmkr.instance_variable_get(:@path)).to be_an_instance_of General::GTemplate
137
+ expect(fmkr.instance_variable_get(:@path).to_s).to eql ft[:path]
138
+
139
+ # Template
140
+ expect(fmkr.instance_variable_get(:@template)).to be_an_instance_of General::GIO
141
+ expect(fmkr.instance_variable_get(:@template).source).to eql "#{@project.config[:directory][:templates]}/#{ft[:template]}"
142
+
143
+ # Extension
144
+ expect(fmkr.instance_variable_get(:@extension)).to eql ft[:extension]
145
+ end
70
146
  end
71
147
  end
72
148
 
73
- # Performing task
74
- context 'with a task maker name given' do
75
- it 'performs the task of the given name with the given arguments' do
76
- @project.make :module, path: @path
77
- [@header, @source].each do |file|
78
- expect(File).to be_file(file[:out])
79
- expect(IO.read(file[:out])).to eql file[:text]
80
- end
149
+ # Describe Roject::Project#task
150
+ #
151
+ # Creates a task maker with the given name and block
152
+ #
153
+ # Parameter: name - the name of the recipie
154
+ # Parameter: block - the recipie block
155
+ describe '#task' do
156
+ it 'creates a task maker with the given name and block' do
157
+ # Create taskmaker
158
+ @project.task @module[:name], &@module[:block]
159
+
160
+ # Get filemaker
161
+ tmkr = @project.instance_variable_get(:@makers)[@module[:name]]
162
+ expect(tmkr).to be_an_instance_of Roject::TaskMaker
81
163
  end
82
164
  end
83
165
 
84
- # Do afterwards
85
- after :each do FileUtils.rmtree(@project.directories) end
166
+ # Describe Roject::Project#make
167
+ #
168
+ # Runs the maker of the given name with the given args
169
+ #
170
+ # Parameter: name - the name of the maker to run
171
+ # Parameter: args - the args to pass to the file
172
+ describe '#make' do
173
+ # Creating filetype
174
+ context 'with a file maker name given' do
175
+ it 'creates a file of the given type with the given arguments' do
176
+ # Each file type
177
+ [@header, @source].each do |ft|
178
+ # Make Header
179
+ @project.make ft[:name],
180
+ path: @path,
181
+ header_id: @project.c_header_id(@path)
182
+
183
+ # Test output
184
+ expect(File).to be_file(ft[:out])
185
+ expect(IO.read(ft[:out])).to eql ft[:text]
186
+ end
187
+ end
188
+ end
189
+
190
+ # Performing task
191
+ context 'with a task maker name given' do
192
+ it 'performs the task of the given name with the given arguments' do
193
+ # Do task
194
+ @project.make @module[:name], path: @path
195
+
196
+ # Each header
197
+ [@header, @source].each do |file|
198
+ # Test output
199
+ expect(File).to be_file(file[:out])
200
+ expect(IO.read(file[:out])).to eql file[:text]
201
+ end
202
+ end
203
+ end
204
+
205
+ # Do afterwards
206
+ after :each do FileUtils.rmtree ["include", "src"] end
207
+ end
86
208
  end
87
209
  end
data/spec/spec_require.rb CHANGED
@@ -11,71 +11,5 @@ Created: 7 - 8 - 2016
11
11
 
12
12
  =end
13
13
 
14
- # Required libraries
15
- require "json"
16
- require "yaml"
17
-
18
14
  # Required files for spec
19
- require_relative "../lib/parsers"
20
- require_relative "../lib/project"
21
- require_relative "../lib/loadsaveable"
22
-
23
- #-----------------------HASHMOD METHODS------------------------
24
-
25
- # Returns the hash with all of the keys converted to symbols
26
- #
27
- # Parameter: hash - the hash to symbolize
28
- #
29
- # Return: the hash with all of the keys converted to symbols
30
- def symbolized hash
31
- hash.each_pair.collect { |k, v| [k.to_sym, v.is_a?(Hash) ? symbolized(v) : v] }.to_h
32
- end
33
-
34
- # Returns the hash with all of the keys converted to strings
35
- #
36
- # Parameter: hash - the hash to stringify
37
- #
38
- # Return: the hash with all of the keys converted to strings
39
- def stringified hash
40
- hash.each_pair.collect { |k, v| [k.to_s, v.is_a?(Hash) ? stringified(v) : v] }.to_h
41
- end
42
-
43
- #------------------------READER METHODS------------------------
44
-
45
- # Reads JSON from the file with the given filename
46
- #
47
- # Parameter: filename - the name of the file to read
48
- #
49
- # Return: hash parsed from JSON file
50
- def read_json filename
51
- JSON.parse IO.read(filename), symbolize_names: true
52
- end
53
-
54
- # Reads YAML from the file with the given filename
55
- #
56
- # Parameter: filename - the name of the file to read
57
- #
58
- # Return: hash parsed from YAML file
59
- def read_yaml filename
60
- symbolized YAML.load IO.read(filename)
61
- end
62
-
63
- #------------------------WRITER METHODS------------------------
64
-
65
- # Writes the given hash as JSON to the file with the
66
- # given filename
67
- #
68
- # Parameter: filename - the name of the file to write to
69
- # Parameter: hash - the hash to write
70
- def write_json filename, hash
71
- IO.write filename, JSON.pretty_generate(hash, indent: "\t")
72
- end
73
-
74
- # Writes the given hash as YAML to the file with the
75
- # given filename
76
- #
77
- # Parameter: filename - the name of the file to write to
78
- # Parameter: hash - the hash to write
79
- def write_yaml filename, hash
80
- IO.write filename, YAML.dump(stringified(hash))
81
- end
15
+ require_relative "../lib/project"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roject
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anshul Kharbanda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-24 00:00:00.000000000 Z
11
+ date: 2016-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: general
@@ -81,20 +81,15 @@ files:
81
81
  - exp/loadsaveable/foo.json
82
82
  - exp/loadsaveable/foo.yaml
83
83
  - exp/loadsaveable/foo.yml
84
- - exp/project/makers.rb
84
+ - exp/project/_templates/header.general
85
+ - exp/project/_templates/source.general
85
86
  - exp/project/output/testheader.h
86
87
  - exp/project/output/testsource.cpp
87
- - exp/project/project.yaml
88
- - exp/project/templates/header.general
89
- - exp/project/templates/source.general
88
+ - exp/project/project.rb
90
89
  - lib/helpers.rb
91
- - lib/loadsaveable.rb
92
- - lib/maker.rb
93
- - lib/parsers.rb
90
+ - lib/makers.rb
94
91
  - lib/project.rb
95
92
  - lib/roject.rb
96
- - spec/loadsaveable_spec.rb
97
- - spec/parsers_spec.rb
98
93
  - spec/project_spec.rb
99
94
  - spec/spec_require.rb
100
95
  homepage:
@@ -1,21 +0,0 @@
1
- # Header file
2
- file :header,
3
- path: "include/@(project_name)/@(path)",
4
- template: "templates/header.general",
5
- extension: "h"
6
-
7
- # Source file
8
- file :source,
9
- path: "src/@(path)",
10
- template: "templates/source.general",
11
- extension: "cpp"
12
-
13
- # Module includes a source and include
14
- task :module do |args|
15
- # Add header id
16
- args[:header_id] = c_header_id(args[:path])
17
-
18
- # Create source and header
19
- make :header, args
20
- make :source, args
21
- end
@@ -1,9 +0,0 @@
1
- ---
2
- project_name: Dre
3
- author: Anshul Kharbanda
4
- created: 7 - 23 - 2016
5
- short_description: Forgot about Dre.
6
- long_description: Nowadays everybody wanna talk like they got somethin' to say but nothin' comes out when they move their lips just a bunch of gibberish and they all acting like they forgot about Dre.
7
- directories:
8
- - include
9
- - src
data/lib/loadsaveable.rb DELETED
@@ -1,121 +0,0 @@
1
- =begin
2
-
3
- Program: Roject
4
-
5
- Roject is a programming project manager written in Ruby.
6
- With Roject, you can create and edit projects based on templates
7
- using simple commands without a heavy IDE.
8
-
9
- Author: Anshul Kharbanda
10
- Created: 7 - 8 - 2016
11
-
12
- =end
13
-
14
- # Parsers
15
- require_relative "parsers"
16
-
17
- # Roject is a programming project manager written in Ruby.
18
- #
19
- # Author: Anshul Kharbanda
20
- # Created: 7 - 8 - 2016
21
- module Roject
22
- # Implementing objects can be loaded from and saved to files in
23
- # any of the supported data storage formats.
24
- #
25
- # Formats: json, yaml
26
- #
27
- # Note: Implementing objects must have a constructor with takes a single hash
28
- # argument and respond to the :hash method which returns a hash of the
29
- # data that needs to be saved
30
- #
31
- # Author: Anshul Kharbanda
32
- # Created: 7 - 10 - 2016
33
- module LoadSaveable
34
- # Methods that are implemented at the class level
35
- #
36
- # Author: Anshul Kharbanda
37
- # Created: 7 - 10 - 2016
38
- module ClassMethods
39
- # Opens the object from a file, evaluates the given
40
- # block in the context of the object, and saves the object.
41
- # If no block is given, returns the object (alias for load)
42
- #
43
- # Parameter: filename - the name of the file to open
44
- # Parameter: block - the block to evaluate within the
45
- # context of the object
46
- #
47
- # Return: the object loaded from the file (if no block given)
48
- def open filename, &block
49
- obj = load(filename)
50
- if block.nil?
51
- return obj
52
- else
53
- obj.instance_exec(&block)
54
- obj.save(filename)
55
- end
56
- end
57
-
58
- # Loads an object from a file of the given filename, parsed
59
- # in the appropriate format based on the extension
60
- #
61
- # Parameter: filename - the name of the file
62
- #
63
- # Return: object loaded from the file
64
- def load filename
65
- self.new Parsers.get(filename).parse IO.read filename
66
- end
67
-
68
- # Defines getter methods for the given names
69
- # each retrieve the value of name in the hash
70
- #
71
- # Parameter: names - the names to define
72
- def get *names
73
- unless names.empty?
74
- names.each do |name|
75
- #add name to attributes list
76
- @attributes ||= []
77
- @attributes << name
78
-
79
- # define method name
80
- define_method(name) { hash[name] }
81
- end
82
- end
83
- end
84
-
85
- # Returns all attributes that are
86
- # part of the LoadSaveable implementation
87
- #
88
- # Return: all attributes that are
89
- # part of the LoadSaveable
90
- # implementation
91
- def attributes
92
- @attributes or []
93
- end
94
- end
95
-
96
- # Methods that are implemented at the instance level
97
- #
98
- # Author: Anshul Kharbanda
99
- # Created: 7 - 10 - 2016
100
- module InstanceMethods
101
- # Saves the object at the given filename, formatted according
102
- # to the extension
103
- #
104
- # Parameter: filename - the name of the file to save to
105
- # (opened in w+ mode). Extension
106
- # determines format
107
- def save filename
108
- IO.write filename, Parsers.get(filename).format(hash)
109
- end
110
- end
111
-
112
- # The implementing reciever will extend ClassMethods
113
- # and include InstanceMethods
114
- #
115
- # Parameter: reciever - the object being included
116
- def self.included(receiver)
117
- receiver.extend ClassMethods
118
- receiver.send :include, InstanceMethods
119
- end
120
- end
121
- end
data/lib/parsers.rb DELETED
@@ -1,145 +0,0 @@
1
- =begin
2
-
3
- Program: Roject
4
-
5
- Roject is a programming project manager written in Ruby.
6
- With Roject, you can create and edit projects based on templates
7
- using simple commands without a heavy IDE.
8
-
9
- Author: Anshul Kharbanda
10
- Created: 7 - 8 - 2016
11
-
12
- =end
13
-
14
- # Parser libraries
15
- require "json"
16
- require "yaml"
17
-
18
- # Roject is a programming project manager written in Ruby.
19
- #
20
- # Author: Anshul Kharbanda
21
- # Created: 7 - 8 - 2016
22
- module Roject
23
- # Contains implementations of parsers for different filetypes
24
- #
25
- # Author: Anshul Kharbanda
26
- # Created: 7 - 11 - 2016
27
- module Parsers
28
- # Generic class parses files of a given type
29
- #
30
- # Subclasses must respond to :parse, :format, and :extension methods
31
- # - parse recieves a string and returns a hash
32
- # - format recieves a hash and returns a string
33
- # - extensions returns all of the supported extensions of the Parser
34
- #
35
- # Author: Anshul Kharbanda
36
- # Created: 7 - 11 - 2016
37
- class Parser
38
- # Matches parser class names
39
- PARSER_REGEX = /(Roject::)?(Parsers::)?(?<name>\w+)Parser/
40
-
41
- # Returns the descendants of Parser
42
- #
43
- # Return: the descendants of Parser
44
- def self.descendants
45
- ObjectSpace.each_object(Class).select {|c| c < self}
46
- end
47
-
48
- # Returns true if the parser is to be used for the given filename
49
- #
50
- # Return: true if the parser is to be used for the given filename
51
- def self.for_filename? filename
52
- extensions.include? File.extname(filename)
53
- end
54
- end
55
-
56
- # Returns the parser for the given filename
57
- #
58
- # Parameter: filename - the name of the file to parse
59
- #
60
- # Return: the parser for the given filename
61
- def self.get(filename)
62
- # Get parser from filename
63
- parser = Parser.descendants.find { |klass| klass.for_filename? filename }
64
-
65
- # Raise LoadError if no parser is found, else return parser
66
- if parser.nil?
67
- raise LoadError, "#{File.extname(filename)} not supported!"
68
- else
69
- return parser
70
- end
71
- end
72
-
73
- #---------------------------------------PARSERS---------------------------------------
74
-
75
- # Parses JSON files
76
- #
77
- # Author: Anshul Kharbanda
78
- # Created: 7 - 11 - 2016
79
- class JSONParser < Parser
80
- # Returns the extensions supported for JSON
81
- #
82
- # Return: the extensions supported for JSON
83
- def self.extensions; [".json"]; end
84
-
85
- # Parses the given json text into a hash
86
- #
87
- # Parameter: text - the json text to parse
88
- #
89
- # Return: the hash parsed from the text
90
- def self.parse(text); JSON.parse text, symbolize_names: true; end
91
-
92
- # Returns the given hash formatted to pretty json
93
- #
94
- # Parameter: hash - the hash to format
95
- #
96
- # Return: the given hash formatted to pretty json
97
- def self.format(hash); JSON.pretty_generate hash, indent: "\t"; end
98
- end
99
-
100
- # Parses YAML files
101
- #
102
- # Author: Anshul Kharbanda
103
- # Created: 7 - 13 - 2016
104
- class YAMLParser < Parser
105
- # Returns the extensions supported for YAML
106
- #
107
- # Return: the extensions supported for YAML
108
- def self.extensions; [".yaml", ".yml"]; end
109
-
110
- # Parses the given yaml text into a hash
111
- #
112
- # Parameter: text - the yaml text to parse
113
- #
114
- # Return: the hash parsed from the text
115
- def self.parse(text); symbolized YAML.load text; end
116
-
117
- # Returns the given hash formatted to yaml
118
- #
119
- # Parameter: hash - the hash to format
120
- #
121
- # Return: the given hash formatted to yaml
122
- def self.format(hash); YAML.dump stringified hash end
123
-
124
- private
125
-
126
- # Returns the hash with all of the keys converted to symbols
127
- #
128
- # Parameter: hash - the hash to symbolize
129
- #
130
- # Return: the hash with all of the keys converted to symbols
131
- def self.symbolized hash
132
- hash.each_pair.collect { |k, v| [k.to_sym, v.is_a?(Hash) ? symbolized(v) : v] }.to_h
133
- end
134
-
135
- # Returns the hash with all of the keys converted to strings
136
- #
137
- # Parameter: hash - the hash to stringify
138
- #
139
- # Return: the hash with all of the keys converted to strings
140
- def self.stringified hash
141
- hash.each_pair.collect { |k, v| [k.to_s, v.is_a?(Hash) ? stringified(v) : v] }.to_h
142
- end
143
- end
144
- end
145
- end
@@ -1,392 +0,0 @@
1
- =begin
2
-
3
- Program: Roject
4
-
5
- Roject is a programming project manager written in Ruby.
6
- With Roject, you can create and edit projects based on templates
7
- using simple commands without a heavy IDE.
8
-
9
- Author: Anshul Kharbanda
10
- Created: 7 - 8 - 2016
11
-
12
- =end
13
-
14
- require_relative "spec_require"
15
-
16
- # Describing LoadSaveable
17
- #
18
- # Implementing objects can be loaded from and saved to files in
19
- # any of the supported data storage formats.
20
- #
21
- # Formats: json
22
- #
23
- # Note: Implementing objects need to respond to the :hash method
24
- # which returns a hash of the data that needs to be saved
25
- #
26
- # Author: Anshul Kharbanda
27
- # Created: 7 - 11 - 2016
28
- describe Roject::LoadSaveable do
29
- #---------------------------------------BEFORE----------------------------------------
30
-
31
- before :all do
32
- # Basic LoadSaveable implementation
33
- class LoadSaveableClass
34
- include Roject::LoadSaveable
35
- def initialize(hash={}); @foo = hash; end
36
- def hash; @foo; end
37
- get :name, :author
38
- end
39
-
40
- @dir = "exp/loadsaveable"
41
- @default_hash = { name: "project", author: "Anshul Kharbanda" }
42
- @modded_hash = { name: "superproject", author: "Super Anshul Kharbanda" }
43
- @pjson_name = "#{@dir}/foo.json"
44
- @pyaml_name = "#{@dir}/foo.yaml"
45
- @pyml_name = "#{@dir}/foo.yml"
46
- @phony_name = "#{@dir}/foo.bar"
47
- end
48
-
49
- #--------------------------------------METHODS-----------------------------------------
50
-
51
- # Describing LoadSaveable::new
52
- #
53
- # Creates a LoadSaveable with the given data hash
54
- #
55
- # Parameter: hash - the data to be contained in the project
56
- #
57
- # Return: the created LoadSaveable
58
- describe "::new" do
59
- context "with no arguments" do
60
- it "creates an empty LoadSaveable" do
61
- project = LoadSaveableClass.new
62
- expect(project).to be_an_instance_of LoadSaveableClass
63
- expect(project.hash).to eql Hash.new
64
- end
65
- end
66
-
67
- context "with a given data hash" do
68
- it "creates a new LoadSaveable with the given data hash" do
69
- project = LoadSaveableClass.new @default_hash
70
- expect(project).to be_an_instance_of LoadSaveableClass
71
- expect(project.hash).to eql @default_hash
72
- end
73
- end
74
- end
75
-
76
- # Describing LoadSaveable::load
77
- #
78
- # Loads an object from a file of the given filename, parsed
79
- # in the appropriate format based on the extension
80
- #
81
- # Parameter: filename - the name of the file
82
- #
83
- # Return: object loaded from the file
84
- describe "::load" do
85
- #------------------------------FILETYPES------------------------------
86
-
87
- context "with a .json filename given" do
88
- it "returns a new LoadSaveable from the json file with the given filename" do
89
- project = LoadSaveableClass.load(@pjson_name)
90
- expect(project).to be_an_instance_of LoadSaveableClass
91
- expect(project.hash).to eql read_json(@pjson_name)
92
- end
93
- end
94
-
95
- context "with a .yaml filename given" do
96
- it "returns a new LoadSaveable from the yaml file with the given filename" do
97
- project = LoadSaveableClass.load(@pyaml_name)
98
- expect(project).to be_an_instance_of LoadSaveableClass
99
- expect(project.hash).to eql read_yaml(@pyaml_name)
100
- end
101
- end
102
-
103
- context "with a .yml filename given" do
104
- it "returns a new LoadSaveable from the yml file with the given filename" do
105
- project = LoadSaveableClass.load(@pyml_name)
106
- expect(project).to be_an_instance_of LoadSaveableClass
107
- expect(project.hash).to eql read_yaml(@pyml_name)
108
- end
109
- end
110
-
111
- #-----------------------------UNSUPPORTED-----------------------------
112
-
113
- context "with an unsupported file extension given" do
114
- it "raises LoadError" do
115
- expect { LoadSaveableClass.load(@phony_name) }.to raise_error LoadError
116
- end
117
- end
118
- end
119
-
120
- # Describing LoadSaveable#save
121
- #
122
- # Saves the object at the given filename, formatted according
123
- # to the extension
124
- #
125
- # Parameter: filename - the name of the file to save to
126
- # (opened in w+ mode). Extension
127
- # determines format
128
- describe "#save" do
129
- #-------------------------------BEFORE--------------------------------
130
-
131
- before :each do
132
- @project = LoadSaveableClass.new @modded_hash
133
- end
134
-
135
- #------------------------------FILETYPES------------------------------
136
-
137
- context "with a .json filename given" do
138
- it "saves the project to the given filename in json format" do
139
- @project.save @pjson_name
140
- expect(read_json(@pjson_name)).to eql @modded_hash
141
- end
142
- end
143
-
144
- context "with a .yaml filename given" do
145
- it "saves the project to the given filename in yaml format" do
146
- @project.save @pyaml_name
147
- expect(read_yaml(@pyaml_name)).to eql @modded_hash
148
- end
149
- end
150
-
151
- context "with a .yml filename given" do
152
- it "saves the project to the given filename in yml format" do
153
- @project.save @pyml_name
154
- expect(read_yaml(@pyml_name)).to eql @modded_hash
155
- end
156
- end
157
-
158
- #-----------------------------UNSUPPORTED-----------------------------
159
-
160
- context "with an unsupported file extension given" do
161
- it "raises LoadError" do
162
- expect { @project.save @phony_name }.to raise_error LoadError
163
- end
164
- end
165
-
166
- #-------------------------------AFTER--------------------------------
167
-
168
- after :all do
169
- write_json @pjson_name, @default_hash
170
- write_yaml @pyaml_name, @default_hash
171
- write_yaml @pyml_name, @default_hash
172
- end
173
- end
174
-
175
- # Describing LoadSaveable::open
176
- #
177
- # Opens the object from a file, evaluates the given
178
- # block in the context of the object, and saves the object.
179
- # If no block is given, returns the object (alias for load)
180
- #
181
- # Parameter: filename - the name of the file to open
182
- # Parameter: block - the block to evaluate within the
183
- # context of the object
184
- #
185
- # Return: the object loaded from the file (if no block given)
186
- describe "::open" do
187
- context "with filename and block given" do
188
- #------------------------------FILETYPES------------------------------
189
-
190
- context "when file is .json" do
191
- # Declare project local variable
192
- project = nil
193
-
194
- it "loads a LoadSaveable from the json file with the given filename (calling #load)" do
195
- # Declare modded_hash local variable
196
- mhash = @modded_hash
197
-
198
- # Open project in a block
199
- expect { LoadSaveableClass.open @pjson_name do
200
- # Set project to instance
201
- project = self
202
-
203
- # Modify project
204
- initialize mhash
205
- end }.not_to raise_error
206
- end
207
-
208
- it "evaluates the given block in the context of the loaded LoadSaveable" do
209
- # Check if project was actually self, and it was successfuly modified
210
- expect(project).to be_an_instance_of LoadSaveableClass
211
- expect(project.hash).to eql @modded_hash
212
- end
213
-
214
- it "saves the LoadSaveable when the block ends" do
215
- # Check if the modded project was saved
216
- expect(read_json(@pjson_name)).to eql @modded_hash
217
- end
218
- end
219
-
220
- context "when file is .yaml" do
221
- # Declare project local variable
222
- project = nil
223
-
224
- it "loads a LoadSaveable from the yaml file with the given filename (calling #load)" do
225
- # Declare modded_hash local variable
226
- mhash = @modded_hash
227
-
228
- # Open project in a block
229
- expect { LoadSaveableClass.open @pyaml_name do
230
- # Set project to instance
231
- project = self
232
-
233
- # Modify project
234
- initialize mhash
235
- end }.not_to raise_error
236
- end
237
-
238
- it "evaluates the given block in the context of the loaded LoadSaveable" do
239
- # Check if project was actually self, and it was successfuly modified
240
- expect(project).to be_an_instance_of LoadSaveableClass
241
- expect(project.hash).to eql @modded_hash
242
- end
243
-
244
- it "saves the LoadSaveable when the block ends" do
245
- # Check if the modded project was saved
246
- expect(read_yaml(@pyaml_name)).to eql @modded_hash
247
- end
248
- end
249
-
250
- context "when file is .yml" do
251
- # Declare project local variable
252
- project = nil
253
-
254
- it "loads a LoadSaveable from the yml file with the given filename (calling #load)" do
255
- # Declare modded_hash local variable
256
- mhash = @modded_hash
257
-
258
- # Open project in a block
259
- expect { LoadSaveableClass.open @pyml_name do
260
- # Set project to instance
261
- project = self
262
-
263
- # Modify project
264
- initialize mhash
265
- end }.not_to raise_error
266
- end
267
-
268
- it "evaluates the given block in the context of the loaded LoadSaveable" do
269
- # Check if project was actually self, and it was successfuly modified
270
- expect(project).to be_an_instance_of LoadSaveableClass
271
- expect(project.hash).to eql @modded_hash
272
- end
273
-
274
- it "saves the LoadSaveable when the block ends" do
275
- # Check if the modded project was saved
276
- expect(read_yaml(@pyml_name)).to eql @modded_hash
277
- end
278
- end
279
-
280
- #-----------------------------UNSUPPORTED-----------------------------
281
-
282
- context "when filetype is unsupported" do
283
- it "raises LoadError" do
284
- expect { LoadSaveableClass.open(@phony_name) {} }.to raise_error LoadError
285
- end
286
- end
287
-
288
- after :all do
289
- write_json @pjson_name, @default_hash
290
- write_yaml @pyaml_name, @default_hash
291
- write_yaml @pyml_name, @default_hash
292
- end
293
- end
294
-
295
- context "with filename given and no block given" do
296
- #------------------------------FILETYPES------------------------------
297
-
298
- context "when file is .json" do
299
- it "loads a LoadSaveable from the json file with the given filename (calling #load) and returns it." do
300
- project = LoadSaveableClass.open @pjson_name
301
- expect(project).to be_an_instance_of LoadSaveableClass
302
- expect(project.hash).to eql @default_hash
303
- end
304
- end
305
-
306
- context "when file is .yaml" do
307
- it "loads a LoadSaveable from the yaml file with the given filename (calling #load) and returns it." do
308
- project = LoadSaveableClass.open @pyaml_name
309
- expect(project).to be_an_instance_of LoadSaveableClass
310
- expect(project.hash).to eql @default_hash
311
- end
312
- end
313
-
314
- context "when file is .yml" do
315
- it "loads a LoadSaveable from the yml file with the given filename (calling #load) and returns it." do
316
- project = LoadSaveableClass.open @pyml_name
317
- expect(project).to be_an_instance_of LoadSaveableClass
318
- expect(project.hash).to eql @default_hash
319
- end
320
- end
321
-
322
- #-----------------------------UNSUPPORTED-----------------------------
323
-
324
- context "when filetype is unsupported" do
325
- it "raises LoadError" do
326
- expect { LoadSaveableClass.open @phony_name }.to raise_error LoadError
327
- end
328
- end
329
- end
330
- end
331
-
332
- # Describing LoadSaveable::get
333
- #
334
- # Defines a getter method for the given name
335
- # which retrieves the value of name in the data
336
- # hash
337
- #
338
- # Parameter: name - the name to define
339
- describe '::get' do
340
- before :all do
341
- @hash = { name: "foo", author: "bar", value: "baz" }
342
- end
343
-
344
- it 'defines methods with the given names' do
345
- LoadSaveableClass.get *@hash.each_key
346
-
347
- @hash.each_key do |key|
348
- expect(LoadSaveableClass.method_defined?(key)).to be true
349
- end
350
- end
351
-
352
- it 'defines methods which return the values in the hash at their corresponding names' do
353
- @instance = LoadSaveableClass.new @hash
354
-
355
- @hash.each_pair do |key, value|
356
- expect(@instance.send(key)).to eql value
357
- end
358
- end
359
- end
360
-
361
- # Describing LoadSaveable::attributes
362
- #
363
- # Returns all attributes that are
364
- # part of the LoadSaveable implementation
365
- #
366
- # Return: all attributes that are
367
- # part of the LoadSaveable
368
- # implementation
369
- describe '::attributes' do
370
- context 'with attributes set' do
371
- it 'returns all attributes that are part of the loadsaveable implementation' do
372
- hash = @default_hash
373
- instance = LoadSaveableClass.new hash
374
-
375
- LoadSaveableClass.attributes.each do |attribute|
376
- expect(instance.send(attribute)).to eql hash[attribute]
377
- end
378
- end
379
- end
380
-
381
- context 'with no attributes set' do
382
- it 'returns an empty array' do
383
- class LoadSaveableClass2
384
- include Roject::LoadSaveable
385
- def initialize(hash={}); @bar = hash; end
386
- def hash; @bar; end
387
- end
388
- expect(LoadSaveableClass2.attributes).to be_empty
389
- end
390
- end
391
- end
392
- end
data/spec/parsers_spec.rb DELETED
@@ -1,128 +0,0 @@
1
- =begin
2
-
3
- Program: Roject
4
-
5
- Roject is a programming project manager written in Ruby.
6
- With Roject, you can create and edit projects based on templates
7
- using simple commands without a heavy IDE.
8
-
9
- Author: Anshul Kharbanda
10
- Created: 7 - 8 - 2016
11
-
12
- =end
13
-
14
- # Spec require
15
- require_relative "spec_require"
16
-
17
- # Describing Roject::Parsers
18
- #
19
- # Contains implementations of parsers for different filetypes
20
- #
21
- # Author: Anshul Kharbanda
22
- # Created: 7 - 11 - 2016
23
- describe Roject::Parsers do
24
- #------------------------------------------BEFORE-------------------------------------------
25
-
26
- before :all do
27
- @hash = { foo: "bar", baz: ["Ju", "Jay", "Jaz"] }
28
- end
29
-
30
- #------------------------------------------PARSERS------------------------------------------
31
-
32
- # Describing Roject::Parsers::JSONParser
33
- #
34
- # Parses JSON files
35
- #
36
- # Author: Anshul Kharbanda
37
- # Created: 7 - 11 - 2016
38
- describe '::JSONParser' do
39
-
40
- #----------------------------------BEFORE-----------------------------------
41
-
42
- before :all do
43
- @text = JSON.pretty_generate(@hash, indent: "\t")
44
- @parser = Roject::Parsers::JSONParser
45
- end
46
-
47
- #----------------------------------METHODS----------------------------------
48
-
49
- # Describing Roject::Parsers::JSONParser::parse
50
- #
51
- # Parses the given json text into a hash
52
- #
53
- # Parameter: text - the json text to parse
54
- #
55
- # Return: the hash parsed from the text
56
- describe '::parse' do
57
- it 'parses the given JSON text into a ruby hash' do
58
- expect(@parser.parse(@text)).to eql @hash
59
- end
60
- end
61
-
62
- # Describing Roject::Parsers::JSONParser::format
63
- #
64
- # Returns the object hash formatted to pretty json
65
- #
66
- # Parameter: hash - the hash to format
67
- #
68
- # Return: the given hash formatted to pretty json
69
- describe '::format' do
70
- it 'formats the given hash into pretty json' do
71
- expect(@parser.format(@hash)).to eql @text
72
- end
73
- end
74
- end
75
-
76
- # Describing Roject::Parsers::YAMLParser
77
- #
78
- # Parses JSON files
79
- #
80
- # Author: Anshul Kharbanda
81
- # Created: 7 - 11 - 2016
82
- describe '::YAMLParser' do
83
-
84
- #----------------------------------BEFORE-----------------------------------
85
-
86
- before :all do
87
- @text = YAML.dump(stringified(@hash))
88
- @parser = Roject::Parsers::YAMLParser
89
- end
90
-
91
- #----------------------------------METHODS----------------------------------
92
-
93
- # Describing Roject::Parsers::YAMLParser::parse
94
- #
95
- # Parses the given yaml text into a hash
96
- #
97
- # Parameter: text - the yaml text to parse
98
- #
99
- # Return: the hash parsed from the text
100
- describe '::parse' do
101
- it 'parses the given YAML text into a ruby hash' do
102
- expect(@parser.parse(@text)).to eql @hash
103
- end
104
- end
105
-
106
- # Describing Roject::Parsers::YAMLParser::format
107
- #
108
- # Returns the object hash formatted to yaml
109
- #
110
- # Parameter: hash - the hash to format
111
- #
112
- # Return: the given hash formatted to yaml
113
- describe '::format' do
114
- it 'formats the given hash into yaml' do
115
- expect(@parser.format(@hash)).to eql @text
116
- end
117
- end
118
- end
119
-
120
- #--------------------------------------------GET--------------------------------------------
121
-
122
- describe '::get' do
123
- it 'returns the appropriate parser according to the extension of the given filename' do
124
- expect(Roject::Parsers.get("foo.json")).to eql Roject::Parsers::JSONParser
125
- expect(Roject::Parsers.get("foo.yaml")).to eql Roject::Parsers::YAMLParser
126
- end
127
- end
128
- end