nse_data 0.1.1 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22de3ed7cc3399b101e16132f7be88dc775557eed246ab3d1f68973202acfe39
4
- data.tar.gz: 708446fcffe3a854afced4693d795442eb115bcf975ff4564f17c50491cf93ef
3
+ metadata.gz: 21c958d7054c952556fa1e0bbb44141261a68ecab2e8d5248c559b54bf92150e
4
+ data.tar.gz: 1f3a1d07073957985cb97cc37174bdc1a247f1b50ee14e691c3bdd4df6e889f0
5
5
  SHA512:
6
- metadata.gz: 8b7969d444c186b8aca15431be34c5024f835276f03a16d8fa4e201465c4ee84b5b38a08fba99fb57fb7a771b2b5ca95b4c63671f171685afcf152baec574cc7
7
- data.tar.gz: 560ae057148dfefa964ad19f5c486c39f0e9862eeead183edd82a953af00661e2b0ce51af398d6e913faa875f83bcc17ee8da415eb9ebf755622daa86e41e460
6
+ metadata.gz: 0fa0f5c7860022322fa7df8f08048c64496227ddcaa45860610a0711ff9a4e24906220006dcb0690b0cdaf3d61dfd6228e5ab552262c218ba78d146a36af66f3
7
+ data.tar.gz: 965e60d16d87a3625803096ca3ebae37ad67b4fd02f5be8bc2024bc8fcb68a3ee83ab25e4efc35567f495972ee835eb680130e0359c12090f58bfabcc6898589
data/README.md CHANGED
@@ -1,4 +1,6 @@
1
1
  # NseData
2
+ [![Gem Version](https://badge.fury.io/rb/nse_data.svg)](https://badge.fury.io/rb/nse_data)
3
+
2
4
  ## Table of Contents
3
5
  - [NseData](#nsedata)
4
6
  - [Table of Contents](#table-of-contents)
@@ -1,3 +1,4 @@
1
+ base_url: https://www.nseindia.com/api/
1
2
  apis:
2
3
  all_indices:
3
4
  path: "allIndices"
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'api_wrapper'
4
+
5
+ module NseData
6
+ # Handles API interactions with the NSE using ApiWrapper.
7
+ class NseApiClient
8
+ attr_reader :api_configuration_path, :cache_store
9
+
10
+ # Initializes with optional custom settings.
11
+ #
12
+ # @param api_configuration_path [String] Path to the API configuration file.
13
+ # @param cache_store [Object] Custom cache store for caching responses.
14
+ def initialize(api_configuration_path: nil, cache_store: nil)
15
+ @api_configuration_path = api_configuration_path || default_configuration_path
16
+ @cache_store = cache_store
17
+ configure_api_wrapper
18
+ end
19
+
20
+ # Fetches data from the specified API endpoint.
21
+ #
22
+ # @param endpoint_key [String] Key for the API endpoint.
23
+ # @param force_refresh [Boolean] Skip cache if true.
24
+ # @return [Hash, String] Response data or raises an error if unsuccessful.
25
+ def fetch_data(endpoint_key, force_refresh: false)
26
+ response = ApiWrapper.fetch_data(endpoint_key, force_refresh:)
27
+ handle_response(response)
28
+ end
29
+
30
+ # Returns all API endpoints available in the configuration.
31
+ #
32
+ # @return [Hash] List of endpoints.
33
+ def endpoints
34
+ @endpoints ||= ApiWrapper::ApiManager.new(api_configuration_path).endpoints
35
+ end
36
+
37
+ private
38
+
39
+ # Configures ApiWrapper with the provided settings.
40
+ def configure_api_wrapper
41
+ ApiWrapper.configure do |config|
42
+ config.api_configuration_path = api_configuration_path
43
+ config.cache_store = cache_store if cache_store
44
+ end
45
+ end
46
+
47
+ # Processes the API response.
48
+ #
49
+ # @param response [Faraday::Response] The API response.
50
+ # @return [Hash, String] Parsed response or error message.
51
+ def handle_response(response)
52
+ raise ApiError, "Error: #{response.status} - #{response.body}" unless response.success?
53
+
54
+ response.body
55
+ end
56
+
57
+ # Default path to the API configuration file.
58
+ def default_configuration_path
59
+ File.join(__dir__, 'config', 'api_endpoints.yml')
60
+ end
61
+ end
62
+
63
+ # Custom error class for handling API errors.
64
+ class ApiError < StandardError; end
65
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NseData
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/nse_data.rb CHANGED
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'nse_data/version'
4
- require_relative 'nse_data/api_manager'
5
- require_relative 'nse_data/config/logger'
4
+ require_relative 'nse_data/nse_api_client'
6
5
 
7
6
  # The NseData module serves as the namespace for the NSE Data gem,
8
7
  # which provides an interface to interact with and retrieve stock market data
@@ -11,12 +10,16 @@ module NseData
11
10
  class Error < StandardError; end
12
11
 
13
12
  class << self
14
- # This module provides functionality for accessing NSE data.
13
+ # Caches the instance of NseApiClient.
14
+ def nse_api_client
15
+ @nse_api_client ||= NseApiClient.new
16
+ end
17
+
18
+ # Dynamically define fetch methods for each API endpoint.
15
19
  def define_api_methods
16
- api_manager = APIManager.new
17
- api_manager.endpoints.each_key do |method_name|
18
- define_singleton_method("fetch_#{method_name}") do
19
- api_manager.fetch_data(method_name).body
20
+ nse_api_client.endpoints.each_key do |method_name|
21
+ define_singleton_method("fetch_#{method_name}") do |force_refresh: false|
22
+ nse_api_client.fetch_data(method_name, force_refresh:)
20
23
  end
21
24
  end
22
25
  end
@@ -25,41 +28,19 @@ module NseData
25
28
  #
26
29
  # @return [Array] An array of endpoint names.
27
30
  def list_all_endpoints
28
- @list_all_endpoints ||= APIManager.new.load_endpoints
29
- end
30
-
31
- # Configure the logger for the NseData gem.
32
- #
33
- # This method allows users to customize the logger used throughout the library.
34
- # To use it, call `NseData.configure` and provide a block to set up the logger.
35
- #
36
- # Example:
37
- #
38
- # NseData.configure do |config|
39
- # custom_logger = Logger.new('nse_data.log')
40
- # custom_logger.level = Logger::DEBUG
41
- # config.logger = custom_logger
42
- # end
43
- #
44
- # @yieldparam [NseData::Config::Logger] config The configuration object to be customized.
45
- def configure
46
- @logger_config ||= Config::Logger.new
47
- yield(@logger_config) if block_given?
31
+ nse_api_client.endpoints
48
32
  end
49
33
 
50
- # Access the configured logger.
34
+ # Fetches data from a specific API endpoint.
51
35
  #
52
- # This method returns the Logger instance configured through `NseData.configure`.
53
- #
54
- # @return [Logger] The configured Logger instance.
55
- # @raise [RuntimeError] If the logger has not been configured.
56
- def logger
57
- @logger_config&.logger || (raise 'Logger not configured. Please call NseData.configure first.')
36
+ # @param endpoint [String] The endpoint key.
37
+ # @param force_refresh [Boolean] Skip cache if true.
38
+ # @return [Hash, String] The API response.
39
+ def fetch_data(endpoint, force_refresh: false)
40
+ nse_api_client.fetch_data(endpoint, force_refresh:)
58
41
  end
59
42
  end
60
43
 
61
- # Initialize configuration with default settings.
62
- @logger_config = Config::Logger.new
44
+ # Define API methods at runtime.
45
+ define_api_methods
63
46
  end
64
-
65
- NseData.define_api_methods
data/nse_data.gemspec CHANGED
@@ -29,6 +29,5 @@ Gem::Specification.new do |spec|
29
29
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
30
  spec.require_paths = ['lib']
31
31
 
32
- spec.add_dependency 'faraday', '~> 2.11'
33
- spec.add_dependency 'faraday-http-cache', '~> 2.5', '>= 2.5.1'
32
+ spec.add_dependency 'api_wrapper'
34
33
  end
metadata CHANGED
@@ -1,49 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nse_data
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sonu Saha
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-10 00:00:00.000000000 Z
11
+ date: 2024-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: faraday
14
+ name: api_wrapper
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.11'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.11'
27
- - !ruby/object:Gem::Dependency
28
- name: faraday-http-cache
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '2.5'
34
17
  - - ">="
35
18
  - !ruby/object:Gem::Version
36
- version: 2.5.1
19
+ version: '0'
37
20
  type: :runtime
38
21
  prerelease: false
39
22
  version_requirements: !ruby/object:Gem::Requirement
40
23
  requirements:
41
- - - "~>"
42
- - !ruby/object:Gem::Version
43
- version: '2.5'
44
24
  - - ">="
45
25
  - !ruby/object:Gem::Version
46
- version: 2.5.1
26
+ version: '0'
47
27
  description: Retrieves stock market data from the NSE (National Stock Exchange) of
48
28
  India
49
29
  email:
@@ -90,16 +70,8 @@ files:
90
70
  - doc/method_list.html
91
71
  - doc/top-level-namespace.html
92
72
  - lib/nse_data.rb
93
- - lib/nse_data/api_manager.rb
94
- - lib/nse_data/cache/README.md
95
- - lib/nse_data/cache/cache_policy.rb
96
- - lib/nse_data/cache/cache_store.rb
97
- - lib/nse_data/cache/redis_cache_store.rb
98
73
  - lib/nse_data/config/api_endpoints.yml
99
- - lib/nse_data/config/base.rb
100
- - lib/nse_data/config/logger.rb
101
- - lib/nse_data/http_client/base_client.rb
102
- - lib/nse_data/http_client/faraday_client.rb
74
+ - lib/nse_data/nse_api_client.rb
103
75
  - lib/nse_data/version.rb
104
76
  - nse_data.gemspec
105
77
  homepage: https://github.com/ahasunos/nse_data
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'yaml'
4
- require_relative 'http_client/faraday_client'
5
- require_relative 'cache/cache_policy'
6
- require_relative 'cache/cache_store'
7
-
8
- module NseData
9
- # APIManager class to handle API calls to NSE (National Stock Exchange) India website.
10
- class APIManager
11
- BASE_URL = 'https://www.nseindia.com/api/'
12
-
13
- # Initializes a new instance of the APIManager class.
14
- #
15
- # @param cache_store [CacheStore, RedisCacheStore, nil] The cache store to use for caching.
16
- # If nil, in-memory cache is used.
17
- def initialize(cache_store: nil)
18
- # Initialize cache policy with the provided cache store or default to in-memory cache.
19
- @cache_policy = NseData::Cache::CachePolicy.new(cache_store || NseData::Cache::CacheStore.new)
20
-
21
- # Configure cache policy (e.g., setting endpoints with no cache or custom TTL).
22
- configure_cache_policy
23
-
24
- # Initialize Faraday client with the base URL and cache policy.
25
- @client = NseData::HttpClient::FaradayClient.new(BASE_URL, @cache_policy)
26
-
27
- # Load API endpoints from the configuration file.
28
- @endpoints = load_endpoints
29
- end
30
-
31
- # Fetches data from the specified API endpoint.
32
- #
33
- # @param endpoint_key [String] The key of the API endpoint to fetch data from.
34
- # @param force_refresh [Boolean] Whether to force refresh the data, bypassing the cache.
35
- # @return [Faraday::Response] The response object containing the fetched data.
36
- # @raise [ArgumentError] If the provided endpoint key is invalid.
37
- def fetch_data(endpoint_key, force_refresh: false)
38
- NseData.logger.debug("#{self.class}##{__method__}: fetching data for #{endpoint_key}")
39
- endpoint = @endpoints[endpoint_key]
40
- raise ArgumentError, "Invalid endpoint key: #{endpoint_key}" unless endpoint
41
-
42
- # Use cache policy to fetch data, with an option to force refresh.
43
- @cache_policy.fetch(endpoint['path'], force_refresh:) do
44
- @client.get(endpoint['path'])
45
- end
46
- end
47
-
48
- # Loads the API endpoints from the configuration file.
49
- #
50
- # @return [Hash] The hash containing the loaded API endpoints.
51
- # @raise [RuntimeError] If the configuration file is missing or has syntax errors.
52
- def load_endpoints
53
- yaml_content = YAML.load_file(File.expand_path('config/api_endpoints.yml', __dir__))
54
- yaml_content['apis']
55
- rescue Errno::ENOENT => e
56
- raise "Configuration file not found: #{e.message}"
57
- rescue Psych::SyntaxError => e
58
- raise "YAML syntax error: #{e.message}"
59
- end
60
-
61
- # @return [Hash] The hash containing the loaded API endpoints.
62
- attr_reader :endpoints
63
-
64
- private
65
-
66
- # Configures the cache policy with specific settings.
67
- #
68
- # This method sets endpoints that should not be cached and custom TTL values for specific endpoints.
69
- def configure_cache_policy
70
- # TODO: Review and refine cache policy for endpoints.
71
- # Plan to analyze the API responses and categorize endpoints into:
72
- # - No cache
73
- # - Cacheable
74
- # - Custom TTL
75
-
76
- # Set specific endpoints that should not be cached.
77
- @cache_policy.add_no_cache_endpoint('market_status')
78
-
79
- # Set custom TTL (time-to-live) for specific endpoints.
80
- @cache_policy.add_custom_ttl('equity_master', 600) # Custom TTL: 10 mins
81
- end
82
- end
83
- end
@@ -1,77 +0,0 @@
1
- # Caching Mechanism Usage and Customization
2
-
3
- ## Overview
4
-
5
- The **NseData** gem includes a flexible caching mechanism to improve performance and reduce redundant API calls. This documentation provides an overview of how to use and customize the caching mechanism.
6
-
7
- ## Cache Policy
8
-
9
- The `CachePolicy` class is responsible for managing caching behavior, including setting global TTLs, custom TTLs for specific endpoints, and controlling which endpoints should bypass the cache.
10
-
11
- ### Initializing CachePolicy
12
-
13
- To use caching, you need to initialize the `CachePolicy` with a cache store and optional global TTL:
14
-
15
- ```ruby
16
- require 'nse_data/cache/cache_policy'
17
- require 'nse_data/cache/cache_store'
18
-
19
- # Initialize the cache store (e.g., in-memory cache store)
20
- cache_store = NseData::Cache::CacheStore.new
21
-
22
- # Initialize the CachePolicy with the cache store and a global TTL of 300 seconds (5 minutes)
23
- cache_policy = NseData::Cache::CachePolicy.new(cache_store, global_ttl: 300)
24
- ```
25
-
26
- ### Configuring Cache Policy
27
- #### Adding No-Cache Endpoints
28
- You can specify endpoints that should bypass the cache:
29
- ```ruby
30
- # Add an endpoint to the no-cache list
31
- cache_policy.add_no_cache_endpoint('/no-cache')
32
- ```
33
-
34
- #### Adding Custom TTLs
35
- You can define custom TTLs for specific endpoints:
36
-
37
- ```ruby
38
- # Set a custom TTL of 600 seconds (10 minutes) for a specific endpoint
39
- cache_policy.add_custom_ttl('/custom-ttl', ttl: 600)
40
- ```
41
-
42
- #### Fetching Data with Cache
43
- Use the fetch method to retrieve data with caching applied:
44
-
45
- ```ruby
46
- # Fetch data for an endpoint with optional cache
47
- data = cache_policy.fetch('/some-endpoint') do
48
- # The block should fetch fresh data if cache is not used or is stale
49
- # e.g., perform an API call or other data retrieval operation
50
- Faraday::Response.new(body: 'fresh data')
51
- end
52
- ```
53
- ## Custom Cache Stores
54
- You can extend the caching mechanism to support different types of cache stores. Implement a custom cache store by inheriting from the CacheStore base class and overriding the read and write methods.
55
-
56
- ### Example Custom Cache Store
57
- ```ruby
58
- class CustomCacheStore < NseData::Cache::CacheStore
59
- def read(key)
60
- # Implement custom read logic
61
- end
62
-
63
- def write(key, value, ttl)
64
- # Implement custom write logic
65
- end
66
- end
67
- ```
68
- ### Using a Custom Cache Store
69
- To use a custom cache store, initialize CachePolicy with an instance of your custom cache store:
70
-
71
- ```ruby
72
- # Initialize the custom cache store
73
- custom_cache_store = CustomCacheStore.new
74
-
75
- # Initialize CachePolicy with the custom cache store
76
- cache_policy = NseData::Cache::CachePolicy.new(custom_cache_store, global_ttl: 300)
77
- ```
@@ -1,118 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NseData
4
- module Cache
5
- # CachePolicy manages caching behavior, including cache storage and time-to-live (TTL) settings.
6
- #
7
- # It allows setting global TTLs, custom TTLs for specific endpoints, and controlling which
8
- # endpoints should not use the cache.
9
- #
10
- # @attr_reader [CacheStore] cache_store The cache store used for storing cached data.
11
- class CachePolicy
12
- attr_reader :cache_store
13
-
14
- # Initializes the CachePolicy with a cache store and global TTL.
15
- #
16
- # @param cache_store [CacheStore, RedisCacheStore] The cache store to use for caching.
17
- # @param global_ttl [Integer] The default TTL (in seconds) for caching.
18
- def initialize(cache_store, global_ttl = 300)
19
- @cache_store = cache_store
20
- @global_ttl = global_ttl
21
- @custom_ttls = {}
22
- @no_cache_endpoints = []
23
- end
24
-
25
- # Adds an endpoint that should bypass the cache.
26
- #
27
- # @param endpoint [String] The endpoint to exclude from caching.
28
- def add_no_cache_endpoint(endpoint)
29
- @no_cache_endpoints << endpoint
30
- end
31
-
32
- # Adds a custom TTL for a specific endpoint.
33
- #
34
- # @param endpoint [String] The endpoint to apply a custom TTL to.
35
- # @param ttl [Integer] The custom TTL value in seconds.
36
- def add_custom_ttl(endpoint, ttl = 300)
37
- @custom_ttls[endpoint] = ttl
38
- end
39
-
40
- # Returns the TTL for a specific endpoint. Defaults to the global TTL if no custom TTL is set.
41
- #
42
- # @param endpoint [String] The endpoint to fetch the TTL for.
43
- # @return [Integer] The TTL in seconds.
44
- def ttl_for(endpoint)
45
- @custom_ttls.fetch(endpoint, @global_ttl)
46
- end
47
-
48
- # Determines if caching should be used for the given endpoint.
49
- #
50
- # @param endpoint [String] The endpoint to check.
51
- # @return [Boolean] True if caching is enabled for the endpoint, false otherwise.
52
- def use_cache?(endpoint)
53
- !@no_cache_endpoints.include?(endpoint)
54
- end
55
-
56
- # Fetches the data for the given endpoint, using cache if applicable.
57
- #
58
- # @param endpoint [String] The endpoint to fetch data for.
59
- # @param force_refresh [Boolean] Whether to force refresh the data, bypassing the cache.
60
- # @yield The block that fetches fresh data if cache is not used or is stale.
61
- # @return [Object] The data fetched from cache or fresh data.
62
- def fetch(endpoint, force_refresh: false, &block)
63
- if force_refresh || !use_cache?(endpoint)
64
- fetch_fresh_data(endpoint, &block)
65
- else
66
- fetch_cached_or_fresh_data(endpoint, &block)
67
- end
68
- end
69
-
70
- private
71
-
72
- # Fetches fresh data and writes it to the cache if applicable.
73
- #
74
- # @param endpoint [String] The endpoint to fetch fresh data for.
75
- # @yield The block that fetches fresh data.
76
- # @return [Object] The fresh data.
77
- def fetch_fresh_data(endpoint)
78
- NseData.logger.debug("#{self.class}##{__method__}: fetching fresh data for #{endpoint}")
79
-
80
- fresh_data = yield
81
- cache_fresh_data(endpoint, fresh_data)
82
- fresh_data
83
- end
84
-
85
- # Fetches cached data or fresh data if not available in the cache.
86
- #
87
- # @param endpoint [String] The endpoint to fetch data for.
88
- # @yield The block that fetches fresh data if cache is not used or is stale.
89
- # @return [Object] The cached or fresh data.
90
- def fetch_cached_or_fresh_data(endpoint, &block)
91
- cached_data = @cache_store.read(endpoint)
92
- if cached_data
93
- NseData.logger.debug("#{self.class}##{__method__}: fetching cached data for #{endpoint}")
94
- Faraday::Response.new(body: cached_data)
95
- else
96
- fetch_fresh_data(endpoint, &block)
97
- end
98
- end
99
-
100
- # Writes fresh data to the cache.
101
- #
102
- # @param endpoint [String] The endpoint for which to store the data.
103
- # @param fresh_data [Object] The data to be stored in the cache.
104
- def cache_fresh_data(endpoint, fresh_data)
105
- ttl = determine_ttl(endpoint)
106
- @cache_store.write(endpoint, fresh_data.body, ttl) if fresh_data.is_a?(Faraday::Response)
107
- end
108
-
109
- # Determines the TTL value for the given endpoint.
110
- #
111
- # @param endpoint [String] The endpoint to fetch the TTL for.
112
- # @return [Integer] The TTL value in seconds.
113
- def determine_ttl(endpoint)
114
- @custom_ttls.fetch(endpoint, @global_ttl)
115
- end
116
- end
117
- end
118
- end
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NseData
4
- module Cache
5
- # CacheStore class provides an in-memory caching mechanism.
6
- class CacheStore
7
- def initialize
8
- @store = {}
9
- end
10
-
11
- # Retrieves the cached data for the given key, or fetches fresh data if not cached or expired.
12
- #
13
- # @param key [String] The cache key.
14
- # @param ttl [Integer] The time-to-live in seconds.
15
- # @yield Fetches fresh data if cache is expired or not present.
16
- # @return [Object] The cached data or the result of the block if not cached or expired.
17
- def fetch(key, ttl)
18
- if cached?(key, ttl)
19
- @store[key][:data]
20
- else
21
- fresh_data = yield
22
- store(key, fresh_data, ttl)
23
- fresh_data
24
- end
25
- end
26
-
27
- # Reads data from the cache.
28
- #
29
- # @param key [String] The cache key.
30
- # @return [Object, nil] The cached data, or nil if not present.
31
- def read(key)
32
- cached?(key) ? @store[key][:data] : nil
33
- end
34
-
35
- # Writes data to the cache with an expiration time.
36
- #
37
- # @param key [String] The cache key.
38
- # @param data [Object] The data to cache.
39
- # @param ttl [Integer] The time-to-live in seconds.
40
- def write(key, data, ttl)
41
- store(key, data, ttl)
42
- end
43
-
44
- # Deletes data from the cache.
45
- #
46
- # @param key [String] The cache key.
47
- def delete(key)
48
- @store.delete(key)
49
- end
50
-
51
- private
52
-
53
- # Checks if the data for the given key is cached and not expired.
54
- #
55
- # @param key [String] The cache key.
56
- # @param ttl [Integer] The time-to-live in seconds.
57
- # @return [Boolean] Whether the data is cached and valid.
58
- def cached?(key, ttl = nil)
59
- return false unless @store.key?(key)
60
-
61
- !expired?(key, ttl)
62
- end
63
-
64
- # Checks if the cached data for the given key has expired.
65
- #
66
- # @param key [String] The cache key.
67
- # @param ttl [Integer] The time-to-live in seconds.
68
- # @return [Boolean] Whether the cached data has expired.
69
- def expired?(key, ttl)
70
- stored_time = @store[key][:timestamp]
71
- ttl && (Time.now - stored_time) >= ttl
72
- end
73
-
74
- # Stores the data in the cache.
75
- #
76
- # @param key [String] The cache key.
77
- # @param data [Object] The data to cache.
78
- # @param ttl [Integer] The time-to-live in seconds.
79
- def store(key, data, ttl)
80
- @store[key] = { data:, timestamp: Time.now, ttl: }
81
- end
82
- end
83
- end
84
- end
@@ -1,3 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # TODO: Implement in near future :)
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NseData
4
- module Config
5
- # Base serves as the base class for configuration settings.
6
- #
7
- # It allows for storing and accessing various configuration settings
8
- # through a hash-like interface.
9
- #
10
- # @attr_reader [Hash] settings The hash storing configuration settings.
11
- class Base
12
- attr_reader :settings
13
-
14
- # Initializes the Base with optional initial settings.
15
- #
16
- # @param initial_settings [Hash] Optional hash of initial settings.
17
- def initialize(initial_settings = {})
18
- @settings = initial_settings
19
- end
20
-
21
- # Retrieves a configuration setting by key.
22
- #
23
- # @param key [Symbol, String] The key for the setting.
24
- # @return [Object] The value associated with the key.
25
- def [](key)
26
- @settings[key]
27
- end
28
-
29
- # Sets a configuration setting by key.
30
- #
31
- # @param key [Symbol, String] The key for the setting.
32
- # @param value [Object] The value to set for the key.
33
- def []=(key, value)
34
- @settings[key] = value
35
- end
36
- end
37
- end
38
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'logger'
4
- require 'tempfile'
5
- require_relative 'base'
6
-
7
- module NseData
8
- module Config
9
- # Logger handles configuration specifically for logging.
10
- #
11
- # It inherits from Base to utilize the hash-like configuration
12
- # interface and provides default settings for logging.
13
- #
14
- # @attr_reader [Logger] logger The Logger instance configured by this class.
15
- class Logger < Base
16
- # Creates a default temporary log file.
17
- def self.default_log_file
18
- return $stdout if ENV['NSE_DEV']
19
-
20
- temp_file = Tempfile.new(['nse_data', '.log'])
21
- temp_file.close # Close the file immediately after creation
22
- temp_file.path # Return the file path for the Logger
23
- end
24
-
25
- # Initializes the Logger with a default or custom Logger instance.
26
- #
27
- # @param logger [Logger] Optional custom Logger instance.
28
- def initialize(logger = ::Logger.new(self.class.default_log_file))
29
- super()
30
- @logger = logger
31
- @settings[:logger] = logger
32
- # puts "Log file created at: #{self.class.default_log_file}"
33
- end
34
-
35
- # Retrieves/Sets the Logger instance.
36
- attr_accessor :logger
37
- end
38
- end
39
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module NseData
4
- module HttpClient
5
- # Base class for HTTP clients
6
- class BaseClient
7
- # Initializes a new instance of the BaseClient class.
8
- #
9
- # @param base_url [String] The base URL for the HTTP client.
10
- def initialize(base_url, cache_policy)
11
- @base_url = base_url
12
- @cache_policy = cache_policy
13
- end
14
-
15
- # Sends a GET request to the specified endpoint.
16
- #
17
- # @param endpoint [String] The endpoint to send the GET request to.
18
- # @raise [NotImplementedError] If the method is not implemented by subclasses.
19
- def get(endpoint)
20
- raise NotImplementedError, 'Subclasses must implement the get method'
21
- end
22
-
23
- # TODO: Other HTTP methods like post, put, delete can be added here if needed
24
- end
25
- end
26
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'faraday'
4
- require 'faraday-http-cache'
5
- require 'json'
6
- require_relative 'base_client'
7
-
8
- module NseData
9
- module HttpClient
10
- # FaradayClient class is responsible for making HTTP requests using Faraday.
11
- class FaradayClient < BaseClient
12
- # Sends a GET request to the specified endpoint.
13
- #
14
- # @param endpoint [String] The endpoint to send the request to.
15
- # @param force_refresh [Boolean] Whether to force a cache refresh.
16
- # @return [Faraday::Response] The response object.
17
- def get(endpoint, force_refresh: false)
18
- NseData.logger.debug("#{self.class}##{__method__}: invoking the endpoint #{endpoint}")
19
- # Use the cache policy to determine whether to fetch from cache or refresh.
20
- @cache_policy.fetch(endpoint, force_refresh:) do
21
- handle_connection(endpoint) do |connection|
22
- connection.get(endpoint)
23
- end
24
- end
25
- end
26
-
27
- private
28
-
29
- # Handles the connection to the base URL.
30
- #
31
- # @yield [connection] The Faraday connection object.
32
- # @yieldparam connection [Faraday::Connection] The Faraday connection object.
33
- # @return [Object] The result of the block execution.
34
- # @raise [Faraday::Error] If there is an error with the connection.
35
- def handle_connection(endpoint)
36
- connection = build_faraday_connection(endpoint)
37
- yield(connection)
38
- rescue Faraday::Error => e
39
- NseData.logger.error("#{self.class}##{__method__}: exception is raised - #{e.message}")
40
- handle_faraday_error(e)
41
- end
42
-
43
- def build_faraday_connection(endpoint)
44
- Faraday.new(url: @base_url) do |faraday|
45
- configure_faraday(faraday)
46
- apply_cache_policy(faraday, endpoint) if @cache_policy.use_cache?(endpoint)
47
- faraday.adapter Faraday.default_adapter
48
- end
49
- end
50
-
51
- def configure_faraday(faraday)
52
- faraday.request :json
53
- faraday.headers['User-Agent'] = 'NSEDataClient/1.0'
54
- faraday.response :json
55
- faraday.headers['Accept'] = 'application/json'
56
- end
57
-
58
- def apply_cache_policy(faraday, endpoint)
59
- ttl = @cache_policy.ttl_for(endpoint)
60
- faraday.use :http_cache, store: @cache_policy.cache_store, expire_after: ttl
61
- end
62
-
63
- def handle_faraday_error(error)
64
- raise error.message
65
- end
66
- end
67
- end
68
- end